Trabajo elaborado para la asignatura “Programación y manejo de datos en la era del Big Data” de la Universitat de València durante el curso 2021-2022. El repo del trabajo está aquí.

La página web de la asignatura y los trabajos de mis compañeros pueden verse aquí.


Librería de paquetes

Campeón del mundo

# aqui irá foto y cosillas del campeon de este finde

Historia de la F1

LOGOS DE LA FORMULA 1

Logo de 1985 a 1986

Logo de 1985 a 1986

Logo de 1987 a 1993

Logo de 1987 a 1993

Logo de 1994 a 2017

Logo de 1994 a 2017

Logo Actual

LOGO desde 2018 hasta la actualidad

Coches

datos Protagonistas

#---PREPARACION DE LOS DATOS

pilotos <- rio::import(file = "./datos/drivers.csv")
resultados <- rio::import(file = "./datos/results.csv")
#str(resultados)
#str(pilotos)
#pilotos[, c(1)] <- sapply(pilotos[, c(1)], as.numeric)
#resultados[, c(3,6,9)] <- sapply(resultados[, c(3,6,9)], as.numeric)

#----------------------------------------------------------------------------------
#numero de carreras que ha corrido cada piloto

#explicacion de lo que hago, no se porque la variable sumatorio no la detecta como numerica aunque la pase a numerica, por tanto al ordenar con slice max no funciona, lo que he hecho es usar la funcion arrange, que ordena de menor a mayor, pero como queremos los que mas carreras han corrido, no me sirve de menor a mayor, por tanto he multiplicado la variable del sumatorio por -1, he usado arrange para que los que más carreras tienen salgan primero, y luego he vuelto a multiplicar por -1. luego he cogido mayores de 202 carreras, que son los 20 que más tienen, porque si hago slice se descuadra y te devuelve el df del principio

n_carreras <- resultados %>% group_by(driverId) %>% mutate(numero_carreras = sum(n())) %>% distinct(numero_carreras) %>% arrange(desc(numero_carreras)) #mutate(numero_carreras_final = numero_carreras*-1)

n_carreras_nom <- full_join(n_carreras, pilotos, c ("driverId" = "driverId")) %>% select(driverId, driverRef, numero_carreras)  %>%  filter(numero_carreras >= 202 ) #los 20 qque mas carreras tienen (no funciona usar slice_max)

#--------------------------------------------------------------------------------

#------------------------------------------------------------------------------
# numero de victorias por piloto
victorias <- resultados %>% filter(position == "1") %>% group_by(driverId) %>% mutate(n_victorias = sum(n())) %>% distinct(n_victorias) %>% arrange(desc(n_victorias))#mutate(n_victorias_final = n_victorias*-1)

#aqui fusiono con el df de pilotos para que aparezca el nombre y no sólo el ID del piloto en cuestion, y hago lo mismo que en el apartado de arriba para ordenar
victorias_con_nombre <- full_join(victorias, pilotos, c ("driverId" = "driverId")) %>% select(driverId, nationality, driverRef, n_victorias)  #los 10 con mas victorias, tmp funciona slice_max
mas_victorias <- victorias_con_nombre %>%  filter(n_victorias >= 25 ) 




#-------------------------------------------------

#resultado medio

resultados[, c(7)] <- sapply(resultados[, c(7)], as.numeric)
resultados[is.na(resultados)] <- 25 

resultado_medio <-  full_join(pilotos, resultados,  c ("driverId" = "driverId")) %>% select(driverId, driverRef, position) %>% group_by(driverId) %>% mutate(result_medio = mean(position)) %>% distinct (driverId, driverRef, result_medio) %>% arrange(result_medio)

#resultado medio en clasificacion
resultado_medio_clas <-  full_join(pilotos, resultados,  c ("driverId" = "driverId")) %>% select(driverId, driverRef, grid) %>% group_by(driverId) %>% mutate(result_medio_clas = mean(grid)) %>% distinct (driverId, driverRef, result_medio_clas)  %>% filter(result_medio_clas > 0) %>% arrange(result_medio_clas)  


#numero de vueltas liderando


#puntos por carrera (puntos/carrera)

puntos_x_carrera <-  full_join(pilotos, resultados,  c ("driverId" = "driverId")) %>% select(driverId, driverRef, points) %>% full_join(., n_carreras,  c ("driverId" = "driverId")) %>% group_by(driverId) %>% mutate(total_puntos = sum(points)) %>% distinct(driverId, driverRef, numero_carreras, total_puntos) %>% mutate(media_puntos = total_puntos/numero_carreras) %>% arrange(desc(media_puntos))

Grafico más victorias

#se necesita "mas_victorias"

#hay que darle formato y mirar lo de animarlo por fecha


gg_mas_victorias <- ggplot(mas_victorias, aes(x = reorder(driverRef, n_victorias), y = n_victorias )) + geom_bar(stat = "identity") + labs(x = "Piloto" , y = "Número de victorias")
gg_mas_victorias
#trabajo --> darle formato chulo, ya veremos este puente si le podemos meter dinámico o que

Parrilla de pilotos 2021 tabla

pilotos <- rio::import(file = "./datos/drivers.csv")
resultados <- rio::import(file = "./datos/results.csv")
carreras <- rio::import(file = "./datos/races.csv")
library(stringr)


pilotos_2021 <- full_join(carreras, resultados, c("raceId" = "raceId") ) %>% 
  full_join(.,pilotos, c("driverId"="driverId")) %>% 
  filter(year=="2021") %>% 
  select(forename,surname, year) %>% distinct(forename,surname) %>% na.omit() %>% arrange(surname) %>% str_replace_all(., "é", "é") %>% str_replace_all(., "ä", "ä") %>% str_replace_all(., "ö", "ö")

nombres_normales <- c("Alonso", "Bottas", "Gasly", "Giovinazzi", "Hamilton", "Latifi", "Leclerc", "Mazepin", "Norris", "Ocon", "Pérez", "Räikkönen", "Ricciardo", "Russell", "Sainz", "Schumacher", "Stroll", "Tsunoda", "Verstappen", "Vettel")

pilotos_2021 <-  full_join(carreras, resultados, c("raceId" = "raceId") ) %>% 
  full_join(.,pilotos, c("driverId"="driverId")) %>% 
  filter(year=="2021") %>% 
  select(forename,surname, year) %>% distinct(forename,surname) %>% na.omit() %>% arrange(surname) %>% add_column(nombres_normales)  
 

# Pérez
# Räikkönen
fotos_pil_2021 <- c("./imagenes/pilotos/alonso.png", "./imagenes/pilotos/bottas.png", "./imagenes/pilotos/gasly.png", "./imagenes/pilotos/giovinazzi.jpg", "./imagenes/pilotos/hamilton.png", "./imagenes/pilotos/latifi.png", "./imagenes/pilotos/leclerc.png", "./imagenes/pilotos/mazepin.png", "./imagenes/pilotos/norris.png", "./imagenes/pilotos/ocon.jpg", "./imagenes/pilotos/perez.png", "./imagenes/pilotos/raikkonen.png", "./imagenes/pilotos/ricciardo.png", "./imagenes/pilotos/russell.png", "./imagenes/pilotos/sainz.png", "./imagenes/pilotos/mick.png", "./imagenes/pilotos/stroll.png", "./imagenes/pilotos/tsunoda.png", "./imagenes/pilotos/verstappen.jpg", "./imagenes/pilotos/vettel.png")

fotos_pais_2021 <- c("./imagenes/paises/espanya.png", "./imagenes/paises/finlandia.png", "./imagenes/paises/francia.png", "./imagenes/paises/italia.png","./imagenes/paises/uk.png", "./imagenes/paises/canada.png","./imagenes/paises/monaco.png", "./imagenes/paises/rusia.png","./imagenes/paises/uk.png", "./imagenes/paises/francia.png","./imagenes/paises/mexico.png", "./imagenes/paises/finlandia.png","./imagenes/paises/australia.png", "./imagenes/paises/uk.png","./imagenes/paises/espanya.png", "./imagenes/paises/alemania.png","./imagenes/paises/canada.png", "./imagenes/paises/japon.png","./imagenes/paises/holanda.png", "./imagenes/paises/alemania.png")

fotos_esc_2021 <- c("./imagenes/escuderias/alpine.png","./imagenes/escuderias/mercedes.png","./imagenes/escuderias/alphatauri.png", "./imagenes/escuderias/alfaromeo.jpg","./imagenes/escuderias/mercedes.png", "./imagenes/escuderias/williams.png","./imagenes/escuderias/ferrari.png", "./imagenes/escuderias/haas.png","./imagenes/escuderias/mclaren.png", "./imagenes/escuderias/alpine.png","./imagenes/escuderias/redbull.png", "./imagenes/escuderias/alfaromeo.jpg","./imagenes/escuderias/mclaren.png", "./imagenes/escuderias/williams.png","./imagenes/escuderias/ferrari.png", "./imagenes/escuderias/haas.png","./imagenes/escuderias/aston.png", "./imagenes/escuderias/alphatauri.png","./imagenes/escuderias/redbull.png", "./imagenes/escuderias/aston.png")

pilotos_2021 <- pilotos_2021 %>%
  add_column(fotos_pil_2021, fotos_pais_2021, fotos_esc_2021) %>% select(nombres_normales, fotos_pil_2021, fotos_pais_2021, fotos_esc_2021)

library(gt)
mundial_2021 <- pilotos_2021 %>% gt() %>% text_transform( locations = cells_body(columns = c(fotos_pil_2021)), fn = function(x) {gt::local_image(x, height = 80)}) %>% text_transform( locations = cells_body(columns = c(fotos_pais_2021)), fn = function(x) {gt::local_image(x, height = 80)}) %>% text_transform( locations = cells_body(columns = c(fotos_esc_2021)), fn = function(x) {gt::local_image(x, height = 80)}) %>% tab_header(title = md("**Pilotos 2021**"), subtitle = md("Parrilla")) %>%   cols_label(
    nombres_normales = html(""),
    fotos_pil_2021 = html(""),
    fotos_pais_2021 = html(""),
    fotos_esc_2021 = html("")) %>%  
  tab_options(table.background.color = "gray13",   table.font.color.light = "cyan") %>% 
  cols_align(align = "center",
  columns = everything())


mundial_2021
Pilotos 2021
Parrilla
Alonso
Bottas
Gasly
Giovinazzi
Hamilton
Latifi
Leclerc
Mazepin
Norris
Ocon
Pérez
Räikkönen
Ricciardo
Russell
Sainz
Schumacher
Stroll
Tsunoda
Verstappen
Vettel

Españoles por la F1

#--------------------------------------------------------------------------------------
#pilotos españoles

pilotos <- rio::import(file = "./datos/drivers.csv")

pilotos_esp <- pilotos %>% filter(nationality == "Spanish") %>% select(driverId, driverRef, nationality) 


#mas victorias de pilotos españoles
mas_victorias_esp <- full_join(victorias_con_nombre, pilotos, c ("driverId" = "driverId")) %>% filter(nationality.x == "Spanish") %>%  select(driverId, driverRef.x, n_victorias, nationality.x) 


#-------------------------------------------------------------------------------------------

Escuderías campeonas

Por tamaño

#datos de escuderias pa quien quiera hacer algo
#escuderias <- rio::import(file = "./datos/constructors.csv")
#escuderias2 <- rio::import(file = "./datos/constructor_standings.csv")
#result_escuderias <- rio::import(file = "./datos/constructor_results.csv")

#pilotos <- rio::import(file = "./datos/drivers.csv")
#resultados <- rio::import(file = "./datos/results.csv")
#carreras <- rio::import(file = "./datos/races.csv")
#escuderiasesp <- escuderias %>% filter(nationality == "Spanish") #escuderias españolas

#campeones_esc <- full_join(pilotos, resultados, c("driverId" = "driverId")) %>% full_join(., carreras, c("raceId" = "raceId")) %>% select(driverId, driverRef, nationality, constructorId, points, year, round) %>% full_join(., escuderias, c("constructorId" = "constructorId")) %>% select(driverId, driverRef, nationality.x, constructorId, points, year, name, round) %>%  group_by(year, driverRef) %>%  mutate(puntos_totales = cumsum(points)) %>% ungroup() %>% group_by(year) %>% slice_max(puntos_totales, n=1) %>% select(name, driverRef) %>% group_by(name, driverRef) %>% mutate(total_camp = sum( NN = n())) %>% arrange(name) 


#campeones_esc <- campeones_esc[!(campeones_esc$driverRef == 'max_verstappen'),] 

#library(treemap)
#library(d3treeR)


# basic treemap
#gg_esc_campeones <- treemap(campeones_esc,
            #index=c("name","driverRef"),
            #vSize="total_camp",
            #type="index",
            #vColor = "name",
            #fontsize.labels=c(25,17),
            #bg.labels=c("transparent"),
            #palette = "Set2",
            #align.labels=list(
              #c("center", "center"), 
              #c("center", "bottom")),
            #title = "Escuderías con más campeones",
            #title.legend = "Escuderías")   
inter_camp <- d3tree2(gg_esc_campeones ,  rootname = "Escuderías y Campeones")
inter_camp

En valores absolutos

campeones_esc <- full_join(pilotos, resultados, c("driverId" = "driverId")) %>% full_join(., carreras, c("raceId" = "raceId")) %>% select(driverId, driverRef, nationality, constructorId, points, year, round) %>% full_join(., escuderias, c("constructorId" = "constructorId")) %>% select(driverId, driverRef, nationality.x, constructorId, points, year, name, round) %>%  group_by(year, driverRef) %>%  mutate(puntos_totales = cumsum(points)) %>% ungroup() %>% group_by(year) %>% slice_max(puntos_totales, n=1) %>% ungroup() %>% count(name) %>% arrange(desc(n))


ggplot(campeones_esc, aes(x = reorder(name,n),y = n)) + geom_bar(stat = "identity") + coord_flip()

Alonso (el nano)

#alonso vs compañeros de equipo

pilotos <- rio::import(file = "./datos/drivers.csv")
resultados <- rio::import(file = "./datos/results.csv")
escuderias <- rio::import(file = "./datos/constructors.csv")
carreras <- rio::import(file = "./datos/races.csv")

alovsall <- full_join(pilotos, resultados, c ("driverId" = "driverId")) %>%  select(driverRef, resultId, raceId, constructorId, position, points) %>% full_join(., escuderias, c ("constructorId" = "constructorId")) %>% select(driverRef, resultId, raceId, constructorId, position, position, points, name) %>% full_join(., carreras, c ("raceId" = "raceId")) %>% select(driverRef, resultId, raceId, constructorId, position, position, points, name.x, year, round)

#alo_vs_marques <- alovsall %>% filter(year == 2001, driverRef %in% c("alonso", "marques"), round <= 14)

alo_vs_trulli <- alovsall %>% filter(year %in% c(2003, 2004), driverRef %in% c("alonso", "trulli")) %>% slice(1:15, 17:67) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_fisichella <- alovsall %>% filter(year %in% c(2005, 2006), driverRef %in% c("alonso", "fisichella"))  %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_hamilton <- alovsall %>% filter(year %in% c(2007) ,driverRef %in% c("alonso", "hamilton"))  %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_piquet <- alovsall %>% filter(year %in% c(2008, 2009), driverRef %in% c("alonso", "piquet_jr")) %>% slice(1:28, 36:63) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

#alo_vs_grosjean <- alovsall %>% filter(year == 2009, driverRef %in% c("alonso", "grosjean"), round >= 11)

alo_vs_massa <- alovsall %>% filter(year %in% c(2010, 2011, 2013), driverRef %in% c("alonso", "massa")) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_raikkonen <- alovsall %>% filter(year == 2014, driverRef %in% c("alonso", "raikkonen")) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_button <- alovsall %>% filter(year %in% c(2015, 2016), driverRef %in% c("alonso", "button")) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

alo_vs_vandoorne <- alovsall %>% filter(year %in% c(2017, 2018), driverRef %in% c("alonso", "vandoorne")) %>% slice(1:45, 47:81) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points))%>% ungroup() 

alo_vs_ocon <- alovsall %>% filter(year == 2021, driverRef %in% c("alonso", "ocon")) %>% group_by(driverRef, year) %>% mutate(puntos_acumulados = cumsum(points)) %>% ungroup()

ALO_VS_ALL <- full_join(alo_vs_trulli, alo_vs_fisichella, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round" , "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_hamilton, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_piquet, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_massa, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados"))  %>% 
  full_join(., alo_vs_raikkonen, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_button, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_vandoorne, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados")) %>% 
  full_join(., alo_vs_ocon, c("driverRef"= "driverRef", "resultId" = "resultId", "raceId" = "raceId", "constructorId" = "constructorId", "position" = "position", "points" = "points", "name.x" = "name.x", "year" = "year", "round" = "round", "puntos_acumulados" = "puntos_acumulados"))

objetos_no_borrar <- c("ALO_VS_ALL", "n_carreras_nom", "victorias_con_nombre")
rm(list = ls()[!ls() %in% objetos_no_borrar])


gc() #instruccion para que cargue el grafico, al ser tan complejo da error de no sé qué pero con esto funciona
#>           used (Mb) gc trigger  (Mb) max used  (Mb)
#> Ncells 1752187 93.6    3337622 178.3  3337622 178.3
#> Vcells 4253971 32.5   14786712 112.9 14771448 112.7
ggalo_vs_all <- ggplot(data = ALO_VS_ALL, aes(round, puntos_acumulados, color = driverRef)) +
  geom_line() +
  geom_point() + 
  labs(title = "Alonso contra el mundo",
       subtitle = "le das un carton con ruedas y aún te saca puntos",
       y = "Puntos", x = "") + facet_wrap( ~ year) + transition_reveal(round)

#ggalo_vs_all

Campeones del mundo

pilotos <- rio::import(file = "./datos/drivers.csv")
resultados <- rio::import(file = "./datos/results.csv")
escuderias <- rio::import(file = "./datos/constructors.csv")
carreras <- rio::import(file = "./datos/races.csv")



campeones <- full_join(pilotos, resultados, c("driverId" = "driverId")) %>% full_join(., carreras, c("raceId" = "raceId")) %>% select(driverId, driverRef, nationality, constructorId, points, year, round) %>% full_join(., escuderias, c("constructorId" = "constructorId")) %>% select(driverId, driverRef, nationality.x, constructorId, points, year, name, round) %>%  group_by(year, driverRef) %>%  mutate(puntos_totales = cumsum(points)) %>% ungroup() %>% group_by(year) %>% slice_max(puntos_totales, n=1) %>% ungroup() %>% group_by(driverRef)%>% mutate(total_campeonatos = sum(NN = n())) %>% distinct(driverRef, nationality.x, total_campeonatos) %>% arrange(nationality.x, total_campeonatos)
  
campeones <- campeones[!(campeones$driverRef == 'max verstappen'),]
id <- rownames(campeones)
campeones <- cbind(id=id, campeones)
campeones[, c(1)] <- sapply(campeones[, c(1)], as.numeric)




label_campeones <- campeones
number_of_bar <- nrow(label_campeones)

angle <- 90 - 360 * (label_campeones$id-0.5) /number_of_bar     # I substract 0.5 because the letter must have the angle of the center of the bars. Not extreme right(1) or extreme left (0)
label_campeones$hjust <- ifelse( angle < -90, 1, 0)
label_campeones$angle <- ifelse(angle < -90, angle+180, angle)



base_campeones <- campeones %>% 
  group_by(nationality.x) %>% 
  summarise(start=min(id), end=max(id)) %>% 
  rowwise() %>% 
  mutate(title=mean(c(start, end)))

grid_campeones <- base_campeones
grid_campeones$end <- grid_campeones$end[ c( nrow(grid_campeones), 1:nrow(grid_campeones)-1)] + 1
grid_campeones$start <- grid_campeones$start - 1
grid_campeones <- grid_campeones[-1,]

gg_circ_victorias <- ggplot(campeones, aes(x=as.factor(year), y=total_campeonatos, fill=nationality.x, color = nationality.x)) + geom_bar(aes(x=as.factor(id), y=total_campeonatos, fill=nationality.x), stat="identity", alpha=0.5) +
  
  geom_segment(data=grid_campeones, aes(x = 0, y = 8, xend = 32, yend = 8), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 0, y = 6, xend = 32, yend = 6), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 0, y = 4, xend = 32, yend = 4), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 0, y = 2, xend = 32, yend = 2), colour = "grey", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  
  annotate("text", x = rep(max(campeones$id),4), y = c(2, 4, 6, 8), label = c("2", "4", "6", "8") , color="white", size=3 , angle=0, fontface="bold", hjust=1) +
  
   geom_bar(aes(x=as.factor(id), y=total_campeonatos, fill=nationality.x), stat="identity", alpha=0.5) +
  ylim(-10,21) +
  theme_minimal() +
  theme(
    legend.position = "none",
    axis.text = element_blank(),
    axis.title = element_blank(),
    panel.grid = element_blank(),
    plot.margin = unit(rep(-1,4), "cm") ) +
  coord_polar() + 
  geom_text(data=label_campeones, aes(x=id, y=10, label=driverRef, hjust=hjust), color="white", fontface="bold",alpha=0.6, size=3.5, angle= label_campeones$angle, inherit.aes = FALSE ) +

  geom_segment(data=grid_campeones, aes(x = 0.70, y = -1, xend = 2.45, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE )  +
  geom_segment(data=grid_campeones, aes(x = 2.6, y = -1, xend = 3.55, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 3.65, y = -1, xend = 5.45, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 5.55, y = -1, xend = 7.35, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 7.5, y = -1, xend = 10.50, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 10.7, y = -1, xend = 19.20, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 19.4, y = -1, xend = 20.3, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 20.45, y = -1, xend = 23.4, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) + 
  geom_segment(data=grid_campeones, aes(x = 23.65, y = -1, xend = 24.35, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) + 
  geom_segment(data=grid_campeones, aes(x = 24.60, y = -1, xend = 27, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 27.2, y = -1, xend = 29.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 29.7, y = -1, xend = 30.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) + 
  geom_segment(data=grid_campeones, aes(x = 30.7, y = -1, xend = 31.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 31.7, y = -1, xend = 32.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) +
  geom_segment(data=grid_campeones, aes(x = 32.7, y = -1, xend = 33.5, yend = -1), colour = "white", alpha=1, size=0.3 , inherit.aes = FALSE ) + theme(legend.text = element_text(colour = "white"),
    legend.title = element_text( colour = "white"), 
     legend.background = element_rect(fill = "gray13", colour = "gray13"),
    legend.key = element_rect(fill = "gray13"),
    legend.position = "right",
    panel.background = element_rect(fill = "gray13" , colour = "gray13"),
    plot.background = element_rect(fill = "gray13" , colour = "gray13"))

templos y tiempos (temp 2021) globo interactivo

carreras <- rio::import(file = "./datos/races.csv")
circuitos <- rio::import(file = "./datos/circuits.csv")

carreras_21 <- full_join(carreras,circuitos, c("circuitId" = "circuitId")) %>%
  filter(year=="2020") %>%
  select(round, name.x, name.y, date, location,country, lat, lng, alt) %>%
  arrange(round) %>% 
  mutate(round2 = round) 

carreras_21_v2 <- carreras_21[, c(1, 4, 10, 2, 3, 5, 6, 7, 8, 9)]
carreras_21_v2 <- carreras_21_v2%>%  unite(. ,variables, c(1, 5, 7), sep = "; ")

#pruebas para mapas, no ejecutar de momento
#library(widgetframe)
#library(leaflet)
#l <- leaflet() %>% setView(lat = 45.61560, lng = 9.281110, zoom=1)
#frameWidget(l) 

#mapaCiudadyPueblomayorinciAcu <- leaflet() %>%
 # setView(lng = -0.243591, lat = 38.821, zoom = 7) %>% 
  #addMarkers(lng = -0.243591, lat = 38.821 , popup = "Vall de Gallinera")%>%
  #setView(lng = -0.418598, lat = 40.2011, zoom = 7) %>% 
  #addMarkers(lng = -0.418598, lat = 40.2011 , popup = "Villahermosa del rio") %>% addTiles()
#mapaCiudadyPueblomayorinciAcu

#MAPA DEL MUNDO DE LA OSTIA NO TOCAR, pongo como comentario para que no tarde tanto al knitear


globo_circ <-create_globe() %>% globe_pov(45.61560, 9.281110) %>% globe_bars(coords(lat, lng, label  = variables, color = round2), data = carreras_21_v2)  %>% scale_bars_color()
#globo_circ

objetos_no_borrar <- c("victorias_con_nombre", "n_carreras_nom", "mas_victorias")
rm(list = ls()[!ls() %in% objetos_no_borrar])
circuitos <- rio::import(file = "./datos/circuits.csv")
tiempos <- rio::import(file = "./datos/lap_times.csv")
carreras <- rio::import(file = "./datos/races.csv")
pilotos <- rio::import(file = "./datos/drivers.csv")

circuitos_gp <- full_join(carreras, circuitos, c("circuitId" = "circuitId")) #asocio las carreras a su circuito
tiemposvuelta_x_carrera <- full_join(circuitos_gp, tiempos, c ("raceId" = "raceId")) #tiempo de las vueltas por cada carrera

tiemposvuelta_x_carrera <- full_join(tiemposvuelta_x_carrera, pilotos, c ("driverId" = "driverId")) %>%  select(circuitId, name.y, driverId, driverRef, time.y, lap,position, year, country) #fusiono con el df de pilotos para asociar cada vuelta al nombre del piloto que la hizo


#calculo el record de cada circuito, filtrando el minimo de los tiempos en cada circuito
record_de_circuito <- tiemposvuelta_x_carrera %>% group_by(name.y) %>% slice_min(time.y, n=1)

#numero de records de circuito que tiene cada piloto
record_x_piloto <- record_de_circuito %>% group_by(driverId) %>% mutate(numero_records = sum(n())) %>% select(driverId, driverRef, numero_records) %>% distinct(driverRef, numero_records) %>% arrange(desc(numero_records))


# meter mapa del mundo con la ubicacion de los circuitos en la temporada 2021
#------------------------------------------------------------

objetos_no_borrar <- c("victorias_con_nombre", "n_carreras_nom", "mas_victorias")
rm(list = ls()[!ls() %in% objetos_no_borrar])

Capítulo oscuro del deporte

#creo df de muertes de formula 1
muertesf1 <- data.frame(
  "orden" = 1:42,
  "driverRef" = c("Chet Miller", "Carl Scaraborough", "Onofre Marimon", "Manny Ayulo", "Bill Vukovich", "Alberto Ascari","Eugenio Castellotti", "Keith Andrews", "Pat O'Connor", "Luigi Musso", "Peter Collins", "Stuart Lewis-Evans", "Jerry Unser", "Bob Cortner", "Ivor Bueb", "Chris Bristow", "Alan Stacey", "Giulio Cabianca", "Wolfgang von Trips", "Carel Godin de Beaufort", "John Taylor", "Lorenzo Bandini", "Bob Anderson", "Jo Schlesser", "Gerhard Mitter", "Piers Courage", "Jochen Rindt", "Jo Siffert", "Roger Williamson", "François Cevert", "Peter Revson", "Helmuth Koinigg", "Mark Donohue", "Tom Pryce", "Ronnie Peterson", "Patrick Depailler", "Gilles Villeneuve", "Riccardo Paletti", "Elio de Angelis", "Roland Ratzenberger", "Ayrton Senna", "Jules Bianchi"),
  "nationality" = c("American", "American", "Argentine", "American", "American", "Italian","Italian", "American", "American", "Italian", "British", "British", "American", "American", "British", "British", "British", "Italian", "German", "Dutch", "British", "Italian" , "British", "French", "German", "British", "Austrian", "Swiss", "British", "French", "American", "Austrian", "American", "British", "Swedish", "French", "Canadian", "Italian", "Italian", "Austrian", "Brazilian", "French"),
  "fecha_muerte" = c(1953, 1953, 1954, 1955, 1955, 1955, 1957, 1957, 1958,1958,1958,1958,1959,1959,1959,1960, 1960,1961,1961,1964,1966, 1967, 1967,1968,1969, 1970,1970,1971,1973,1973,1974,1974,1975,1977,1978,1980,1982,1982,1986,1994,1994,2014))
#no pongo las comillas en los años para que se creen directamente como observaciones numericas

#creo un df con todos los años para luego fusionarlo, ya que no hay muertes todos los años 
anyos <- data.frame(
  "orden" = 1:71,
  "año" = c(1950:2020))

#sumatorio de las muertes por año
muertes_anyo <- muertesf1 %>% group_by(fecha_muerte) %>% mutate(muertesxanyo = sum(n())) %>% distinct(fecha_muerte, muertesxanyo) 

#fusiono los 2 dfs para que tenga en cuenta los años donde no hay muertes
muertesf1_final <- full_join(muertes_anyo, anyos, c("fecha_muerte" = "año")) %>% select(fecha_muerte,muertesxanyo) %>% arrange(fecha_muerte)

#convierto los N/A en 0, es decir, cuando no hay observaciones, ha habido 0 muertes
muertesf1_final[is.na(muertesf1_final)] <- 0

#grafico de las muertes por cada año + la tendencia negativa ea lo largo de la historia
gg_muertes <- ggplot(muertesf1_final, aes(x = fecha_muerte, y = muertesxanyo )) +  geom_bar(stat = "identity", fill = "white", colour = "white") + geom_smooth(colour = "cyan", se = FALSE) + labs(x = "Año" , y = "Número de muertes")  + theme(axis.line = element_line(colour = "white"),
    axis.ticks = element_line(colour = "white"),
    panel.grid.major = element_line(colour = "gray13"),
    panel.grid.minor = element_line(colour = "gray13"),
    axis.title = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    plot.title = element_text(colour = "white"),
    panel.background = element_rect(fill = "gray12",
        colour = "white"), plot.background = element_rect(fill = "gray13")) +labs(colour = "white") + theme(panel.grid.major = element_line(colour = "gray38",
    linetype = "dotted"), panel.grid.minor = element_line(colour = NA),
    plot.title = element_text(size = 25,
        hjust = 0.5)) +labs(title = "Accidentes mortales por año") + geom_text(data = data.frame(x = 2004.10522642875, y = 0.237450516942241, 
    label = "Tendencia negativa"), mapping = aes(x = x, y = y, 
    label = label), colour = "cyan", inherit.aes = FALSE, size = 3)

ggplotly(gg_muertes)

1. Introducción

Tenemos pensado elaborar el trabajo en equipo sobre Formula 1, una competición de la que somos muy aficionados, entre otras cosas por la importancia que tienen los datos a la hora de formalizar las estrategias en la competición.

Remando a contracorriente

#mas posiciones remontadas en una carrera gran premio

tiempos <- rio::import(file = "./datos/lap_times.csv")
carreras <- rio::import(file = "./datos/races.csv")
resultados <- rio::import(file = "./datos/results.csv")
circuitos <- rio::import(file = "./datos/circuits.csv")
pilotos <- rio::import(file = "./datos/drivers.csv")

resultados[, c(6,9)] <- sapply(resultados[, c(6,9)], as.numeric) #transformo variables grid y positionOrder en numerico
str(resultados) # para comprobarlo
#> 'data.frame':    25140 obs. of  18 variables:
#>  $ resultId       : int  1 2 3 4 5 6 7 8 9 10 ...
#>  $ raceId         : int  18 18 18 18 18 18 18 18 18 18 ...
#>  $ driverId       : int  1 2 3 4 5 6 7 8 9 10 ...
#>  $ constructorId  : int  1 2 3 4 1 3 5 6 2 7 ...
#>  $ number         : chr  "22" "3" "7" "5" ...
#>  $ grid           : num  1 5 7 11 3 13 17 15 2 18 ...
#>  $ position       : chr  "1" "2" "3" "4" ...
#>  $ positionText   : chr  "1" "2" "3" "4" ...
#>  $ positionOrder  : num  1 2 3 4 5 6 7 8 9 10 ...
#>  $ points         : num  10 8 6 5 4 3 2 1 0 0 ...
#>  $ laps           : int  58 58 58 58 58 57 55 53 47 43 ...
#>  $ time           : chr  "1:34:50.616" "+5.478" "+8.163" "+17.181" ...
#>  $ milliseconds   : chr  "5690616" "5696094" "5698779" "5707797" ...
#>  $ fastestLap     : chr  "39" "41" "41" "58" ...
#>  $ rank           : chr  "2" "3" "5" "7" ...
#>  $ fastestLapTime : chr  "1:27.452" "1:27.739" "1:28.090" "1:28.603" ...
#>  $ fastestLapSpeed: chr  "218.300" "217.586" "216.719" "215.464" ...
#>  $ statusId       : int  1 1 1 1 1 11 5 5 4 3 ...
#mayores remontadas de la historia, se resta posicion de salida - posicion final
puestos_remontados <- resultados %>% mutate(remontados = grid - positionOrder) %>% select(raceId, driverId, grid, positionOrder, remontados) 


#de toda la historia
circuitos_gp <- full_join(carreras, circuitos, c("circuitId" = "circuitId")) %>% select(circuitId, name.y, raceId, year)

ptos_remont_carrera <- inner_join(puestos_remontados, circuitos_gp)

puestos_remont_piloto <- full_join(pilotos, ptos_remont_carrera, c("driverId" = "driverId")) %>% slice_max(remontados, n=10) %>% select(driverId, driverRef,name.y,year, raceId, grid, positionOrder, remontados)

#------------------------------


# de la hisotoria reciente
circuitos_gp_recient <- full_join(carreras, circuitos, c("circuitId" = "circuitId")) %>% select(circuitId, name.y, raceId, year) %>% filter(year >= 1995)

ptos_remont_carrera_recient <- inner_join(puestos_remontados, circuitos_gp_recient)

puestos_remont_piloto_recient <- full_join(pilotos, ptos_remont_carrera_recient, c("driverId" = "driverId")) %>% slice_max(remontados, n=10) %>% select(driverId, driverRef, name.y, year,raceId, grid, positionOrder, remontados) %>% slice(1:4,6:8,10) %>% arrange(desc(remontados))

ggremontados <- ggplot(puestos_remont_piloto_recient, aes(x = reorder(driverRef, remontados), remontados)) + geom_bar(stat = "identity") + coord_flip() + labs(x = "Pilotos", y = "Nº de puestos remontados" )
ggremontados

objetos_no_borrar <- c("victorias_con_nombre", "n_carreras_nom", "mas_victorias")
rm(list = ls()[!ls() %in% objetos_no_borrar])

ALONSO vs HAMILTON

#se necesita tener cargado "n_carreras_nom", "victorias_con_nombre"
#1234
fotos_ALO_vs_HAM <- c("./imagenes/pilotos/alonso.png", "./imagenes/pilotos/hamilton.png")
fotos_esp_ing <- c("./imagenes/paises/espanya.png", "./imagenes/paises/uk.png")
n_carreras_alo_ham <- n_carreras_nom %>% filter(driverRef %in% c("alonso", "hamilton"))

n_victorias_alo_ham <- victorias_con_nombre %>% filter(driverRef %in% c("alonso", "hamilton"))

alo_vs_ham <- full_join(n_carreras_alo_ham, n_victorias_alo_ham, c("driverRef"= "driverRef")) %>% select( driverRef, numero_carreras, n_victorias) %>% add_column(fotos_esp_ing, fotos_ALO_vs_HAM) 

library(gt)
alo_vs_ham_tabla <- alo_vs_ham %>% gt() %>% text_transform( locations = cells_body(columns = c(fotos_esp_ing)), fn = function(x) {gt::local_image(x, height = 50)}) %>% text_transform( locations = cells_body(columns = c(fotos_ALO_vs_HAM)), fn = function(x) {gt::local_image(x, height = 100)}) %>% tab_header(title = md("**Alonso vs Hamilton**"), subtitle = md("Comparación")) %>%   cols_label(
    driverRef = html(""),
    numero_carreras = html("Nº carreras"),
    n_victorias = html("Nº victorias"),
    fotos_esp_ing = html("País"),
    fotos_ALO_vs_HAM = html("")) %>%  
  tab_options(table.background.color = "gray13",   table.font.color.light = "cyan") %>% 
  cols_align(align = "center",
  columns = everything())

alo_vs_ham_tabla
Alonso vs Hamilton
Comparación
Nº carreras Nº victorias País
alonso 323 32
hamilton 275 98

Audiencias

#audiencias


audiencias <- rio::import(file = "./datos/audienciasF1.csv")


gg_audiencias <- ggplot(audiencias, aes(x=year, y= numero_espectadores)) +
  geom_segment( aes(x=year, xend = year, y=0, yend= numero_espectadores , size = "1")) +
  geom_point( size=5, color="blue", fill=alpha("cyan", 8), alpha=0.7, shape=21, stroke=2) +  
  scale_x_continuous(
    breaks = seq(2004, 2020, 1),
    limits = c(2003, 2021)) + labs(x = "Año", y = "Numero de espectadores" )  + theme(panel.background = element_rect(fill = "gray13"),
    plot.background = element_rect(fill = "gray13")) + theme(axis.line = element_line(colour = "white"),
    panel.grid.major = element_line(colour = "gray20"),
    panel.grid.minor = element_line(colour = "gray20"),
    axis.text = element_text(colour = "white"),
    legend.position = "none") + theme(axis.title = element_text(colour = "white"),
    plot.title = element_text(colour = "white",
        hjust = 0.5)) +labs(title = "Evolución de la audiencia",
    colour = "white") + theme(axis.text.x = element_text(size = 4)) #+ transition_reveal(numero_espectadores)

ggplotly(gg_audiencias)

Presupuestos

#presupuestos

presupuestos <- read_excel("datos/presupuestos.xlsx")

gg_presup <- ggplot(presupuestos, aes(year, Presupuesto, color = Escuderia)) + 
  geom_point() + geom_line() + 
  labs(x = "Año", y = "Presupuesto en €" ) +
    scale_x_continuous(
    breaks = seq(2015, 2023, 1),
    limits = c(2014, 2024)) + 
  scale_y_continuous( breaks = seq(0, 700000000, 100000000),
    limits = c(0, 600000000))  + theme(axis.ticks = element_line(colour = "white"),
    panel.grid.major = element_line(colour = "white",
        linetype = "blank"), panel.grid.minor = element_line(colour = "white",
        linetype = "blank"), axis.title = element_text(size = 14,
        face = "bold", colour = "cyan", vjust = 0.75),
    axis.text = element_text(colour = "white"),
    plot.title = element_text(size = 16,
        face = "bold", colour = "cyan", hjust = 0.5,
        vjust = 0.75), legend.text = element_text(face = "bold",
        colour = "cyan"), legend.title = element_text(size = 13,
        face = "bold", colour = "cyan"),
    panel.background = element_rect(fill = "gray13",
        colour = "white"), plot.background = element_rect(fill = "gray13"),
    legend.key = element_rect(fill = "gray13"),
    legend.background = element_rect(fill = "gray13")) +labs(title = "PRESUPUESTO DE CADA EQUIPO POR TEMPORADA") + theme(panel.grid.major = element_line(colour = NA),
    panel.grid.minor = element_line(colour = NA),
    axis.title = element_text(size = 11),
    plot.title = element_text(size = 14),
    legend.text = element_text(size = 9),
    legend.title = element_text(size = 11),
    panel.background = element_rect(fill = "gray13",
        colour = NA), plot.background = element_rect(fill = "gray13",
        colour = NA)) + theme(legend.key = element_rect(fill = "gray13"),
    legend.background = element_rect(fill = "gray13")) + theme(axis.line = element_line(colour = "gray20",
    linetype = "solid"), panel.grid.major = element_line(colour = "gray15",
    linetype = "solid"))
 
ggplotly(gg_presup) #para que sea interactivo

mapa de coropletas de pilotos por pais (por terminar)

#ESTO QUE VA EN COMENTARIOS VA FUERA

pilotos <- rio::import(file = "./datos/drivers.csv")

nacionalidad <- pilotos %>% group_by(nationality) %>% mutate(numero_compatriotas = sum(n())) %>% distinct(numero_compatriotas) %>% arrange(desc(numero_compatriotas)) %>% 
  str_replace_all(., "British", "United Kingdom") %>% 
  str_replace_all(., "American", "United States") %>% 
  str_replace_all(., "Italian", 'Italy') %>% 
  str_replace_all(., "French" , 'France') %>% 
  str_replace_all(., "German" , 'Germany') %>% 
  str_replace_all(., "Brazilian" , 'Brazil') %>% 
  str_replace_all(., "Argentine" , 'Argentina') %>% 
  str_replace_all(., "Swiss" , 'Switzerland') %>% 
  str_replace_all(., "Belgian" , 'Belgium') %>% 
  str_replace_all(., "South African" , 'South Africa') %>% 
  str_replace_all(., "Japanese" , 'Japan') %>% 
  str_replace_all(., "Australian" , 'Australia') %>%
  str_replace_all(., "Dutch" , 'Netherlands') %>%
  str_replace_all(., "Spanish" , 'Spain') %>%
  str_replace_all(., "Austrian" , 'Austria') %>%
  str_replace_all(., "Canadian" , 'Canada') %>%
  str_replace_all(., "Swedish" , 'Sweden') %>%
  str_replace_all(., "Finnish" , 'Finland') %>%
  str_replace_all(., "New Zealander" , 'New Zealand') %>%
  str_replace_all(., "Mexican" , 'Mexico') %>%
  str_replace_all(., "Irish" , 'Ireland') %>%
  str_replace_all(., "Danish" , 'Denmark') %>%
  str_replace_all(., "Portuguese" , 'Portugal') %>%
  str_replace_all(., "Monegasque" , 'France') %>%
  str_replace_all(., "Rhodesian" , 'Zimbabwe') %>%
  str_replace_all(., "Uruguayan" , 'Uruguay') %>%
  str_replace_all(., "Russian" , 'Russia') %>%
  str_replace_all(., "Colombian" , 'Colombia') %>%
  str_replace_all(., "Venezuelan" , 'Venezuela') %>%
  str_replace_all(., "East German" , 'German') %>%
  str_replace_all(., "Indian" , 'India') %>%
  str_replace_all(., "Thai" , 'Thailand') %>%
  str_replace_all(., "Polish" , 'Poland') %>%
  str_replace_all(., "Monegasque" , 'France') %>%
  str_replace_all(., "Hungarian" , 'Hungary') %>%
  str_replace_all(., "Czech" , 'Czech Rep.') %>%
  str_replace_all(., "Malaysian" , 'Malaysia') %>%
  str_replace_all(., "Chilean" , 'Chile') %>%
  str_replace_all(., "Liechtensteiner" , 'Switzerland') %>%
  str_replace_all(., "American-Italian" , 'United States') %>%
  str_replace_all(., "Argentine-Italian" , 'Argentina') %>%
  str_replace_all(., "Indonesian" , 'Indonesia')

paises_normales <- c("United Kingdom", "United States", "Italy", "France", "Germany", "Brazil", "Argentina", "Switzerland", "Belgium", "South Africa", "Japan", "Australia", "Netherlands", "Spain", "Austria", "Canada", "Sweden", "Finland", "New Zealand", "Mexico", "Ireland", "Denmark", "Portugal", "France", "Zimbabwe", "Uruguay", "Russia", "Colombia", "Venezuela", "Germany", "India", "Thailand", "Poland", "Hungary", "Czech Rep.", "Malaysia", "Chile", "Switzerland", "United States", "Argentina", "Indonesia" )

nacionalidad <- pilotos %>% group_by(nationality) %>% mutate(numero_compatriotas = sum(n())) %>% distinct(numero_compatriotas) %>% arrange(desc(numero_compatriotas)) %>% add_column(paises_normales) %>%  group_by(paises_normales) %>% mutate(total_pilotos = sum(numero_compatriotas)) %>%  distinct(paises_normales, total_pilotos)


library(tmap)
data(World)
world <- World; rm(World)

world <- world[!(world$name %in% c('Greenland', 'Antarctica')),]

pilotos_por_paises <- full_join(nacionalidad, world, c( "paises_normales" = "name")) 

pilotos_por_paises$country <- NULL

pilotos_por_paises[is.na(pilotos_por_paises)] <- 0

gg_pilotos_por_paises <- ggplot(data = pilotos_por_paises, aes(geometry = geometry)) + geom_sf() +
       labs(title = "Pilotos por país",
            caption = "Menor intensidad de color en aquellos paises con más pilotos")

gg_pilotos_por_paises <- gg_pilotos_por_paises + geom_sf(aes(fill = total_pilotos)) + theme(plot.subtitle = element_text(colour = "white"),
    plot.caption = element_text(colour = "white"),
    axis.ticks = element_line(linetype = "blank"),
    panel.grid.major = element_line(linetype = "blank"),
    panel.grid.minor = element_line(linetype = "blank"),
    axis.text = element_text(colour = "gray13"),
    plot.title = element_text(size = 20,
        colour = "white", hjust = 0.5), legend.text = element_text(colour = "white"),
    legend.title = element_text(colour = "white"),
    panel.background = element_rect(fill = "gray13"),
    plot.background = element_rect(fill = "gray13"),
    legend.background = element_rect(fill = "gray13")) +labs(fill = "Nª de pilotos") + theme(panel.background = element_rect(colour = "gray13"),
    plot.background = element_rect(colour = "gray13")) + theme(panel.grid.major = element_line(colour = NA),
    panel.background = element_rect(linetype = "solid"),
    plot.background = element_rect(linetype = "solid")) + scale_fill_gradient2(low = "white", mid = "pink", high = "red", midpoint = .02)

PILOTOS POR PAÍS (MAPA)

Mapa

ggplotly(gg_pilotos_por_paises)

Tabla

nacionalidad %>% gt() %>% tab_header(title = md("**Pilotos por cada país**")) %>% cols_label(
    paises_normales = html("Pais"),
    total_pilotos = html("Nº pilotos")) %>%  
  tab_options(table.background.color = "gray13", table.font.color.light = "cyan")
Pilotos por cada país
Nº pilotos
United Kingdom
165
United States
158
Italy
99
France
77
Germany
53
Brazil
32
Argentina
25
Switzerland
24
Belgium
23
South Africa
23
Japan
20
Australia
17
Netherlands
17
Spain
15
Austria
15
Canada
14
Sweden
10
Finland
9
New Zealand
9
Mexico
6
Ireland
5
Denmark
5
Portugal
4
Zimbabwe
4
Uruguay
4
Russia
4
Colombia
3
Venezuela
3
India
2
Thailand
2
Poland
1
Hungary
1
Czech Rep.
1
Malaysia
1
Chile
1
Indonesia
1

.

THE PLAN

2. Datos

Hemos encontrado en kaggle bastantes conjuntos de datos con los que poder trabajar, pero especialmente este, que posee gran variedad de datos en lo referente a pilotos, resultados, circuitos, tiempos, etc… Consideramos que para empezar a trabajar será suficiente, y en función de como vayamos dirigiendo el trabajo, buscaremos diferentes conjunto de datos con los que apoyarnos.

3. Trabajos en los que nos vamos a basar

Con los datos que hemos encontrado, existen una serie de códigos que ya trabajan con estos datos, especialmente este, que ha conseguido realizar análisis con este conjunto de datos y varias ilustraciones muy llamativas, por lo que podremos tomarlo como referencia durante el inicio del trabajo

“Nadie es más rápido que el nano”

library(magick)
coche1950 <- image_read("./imagenes/coches/1950.jpg") %>% image_scale(., "500") %>%  image_annotate(., "1950", size = 40, gravity = "southwest", color = "white")
coche1960 <- image_read("./imagenes/coches/1960.jpg") %>% image_scale(., "500")%>%  image_annotate(., "1960", size = 40, gravity = "southwest", color = "white")
coche1970 <- image_read("./imagenes/coches/1970.jpg") %>% image_scale(., "500")%>%  image_annotate(., "1970", size = 40, gravity = "southwest", color = "white")
coche1980 <- image_read("./imagenes/coches/1980.jpg") %>% image_scale(., "500")%>%  image_annotate(., "1980", size = 40, gravity = "southwest", color = "white")
coche1990 <- image_read("./imagenes/coches/1990.jpg") %>% image_scale(., "500")%>%  image_annotate(., "1990", size = 40, gravity = "southwest", color = "white")
coche2005 <- image_read("./imagenes/coches/2005.jpg") %>% image_scale(., "500")%>%  image_annotate(., "2005", size = 40, gravity = "southwest", color = "white")
coche2020 <- image_read("./imagenes/coches/2020.jpg") %>% image_scale(., "500")%>%  image_annotate(., "2020", size = 40, gravity = "southwest", color = "white")
coches <- c(coche1950, coche1960, coche1970, coche1980, coche1990, coche2005, coche2020)

image_animate(image_scale(coches), fps = 0.5)

LS0tDQp0aXRsZTogIkFsdCArIEZvcm11bGEgMSINCmF1dGhvcjogIkNheWV0YW5vIFJvbWVybyBNb250ZWFndWRvIChjYXJvbW9uM0BhbHVtbmkudXYuZXMpICBcblxuIEFsZWphbmRybyBHYXJjw61hIFNlZ2FycmEgKGFnYXJzZTRAYWx1bW5pLnV2LmVzKSAgXG4gXG4gQ2FybG9zIEdhcmPDrWEgQ2FzdGlsbGEgKGdhcmNhczhAYWx1bW5pLnV2LmVzKS4gXG5cbiBVbml2ZXJzaXRhdCBkZSBWYWzDqG5jaWEiDQpkYXRlOiAiRGljaWVtYnJlIGRlIDIwMjEgKGFjdHVhbGl6YWRvIGVsIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVknKWApIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgICNjc3M6ICIuL2Fzc2V0cy9teV9jc3NfZmlsZS5jc3MiDQogICAgdGhlbWU6IGRhcmtseQ0KICAgIGhpZ2hsaWdodDogdGFuZ28gDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAzIA0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xsYXBzZWQ6IHRydWUNCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBkZl9wcmludDoga2FibGUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQotLS0NCjwhLS0tIGNodW5rIHBhcmEgcXVlIGxhIGZ1ZW50ZSBzZWEgbGEgb2ZpY2lhbCBkZSBsYSBGb3JtdWxhIDEgLS0+DQpgYGB7Y3NzLCBlY2hvPUZBTFNFfSANCkBmb250LWZhY2Ugew0KICBmb250LWZhbWlseTogRjE7DQogIHNyYzogdXJsKGh0dHBzOi8vd3d3LmZvcm11bGExLmNvbS9ldGMvZGVzaWducy9mb20td2Vic2l0ZS9mb250cy9GMVJlZ3VsYXIvRm9ybXVsYTEtUmVndWxhci50dGYpOw0KfQ0KDQpzcGFuew0KICBmb250LWZhbWlseTogRjE7DQp9DQoNCmF7DQogIGZvbnQtZmFtaWx5OiBGMTsNCn0NCg0KLm5hdi1waWxscz5saS5hY3RpdmU+YTpmb2N1cyB7DQogICAgY29sb3I6ICNmZmZmZmY7DQogICAgYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5Ow0KfQ0KDQouY29udGFpbmVyLWZsdWlkLCAuY29udGFpbmVyLWZsdWlkIGgxIHsNCiAgICBmb250LWZhbWlseTogRjE7DQogICAgbGluZS1oZWlnaHQ6IDEuNzsNCn0NCg0KLmNvbnRhaW5lci1mbHVpZCBwIHsNCiAgICBmb250LWZhbWlseTogRjE7DQogICAgY29sb3I6Y3lhbjsNCn0NCg0KaDEsaDIsaDMsaDQsaDUsaDYscCwgdGFibGUgew0KICBmb250LWZhbWlseTogRjE7DQogIGNvbG9yOiBjeWFuDQp9DQpgYGANCg0KDQoNCmBgYHtyIGNodW5rLXNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGV2YWwgPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICAgI3Jlc3VsdHMgPSAiaG9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgY2FjaGUgPSBGQUxTRSwgY2FjaGUucGF0aCA9ICIvY2FjaGVzLyIsIGNvbW1lbnQgPSAiIz4iLA0KICAgICAgICAgICAgICAgICAgICAgICNmaWcud2lkdGggPSA3LCAjZmlnLmhlaWdodD0gNywgICANCiAgICAgICAgICAgICAgICAgICAgICAjb3V0LndpZHRoID0gNywgb3V0LmhlaWdodCA9IDcsDQogICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2UgPSBUUlVFLCAgZmlnLnNob3cgPSAiaG9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFzcCA9IDAuNjI4LCBvdXQud2lkdGggPSAiNzUlIiwgZmlnLmFsaWduID0gImNlbnRlciIpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZGV2ID0gInBuZyIsIGRldi5hcmdzID0gbGlzdCh0eXBlID0gImNhaXJvLXBuZyIpKQ0KYGBgDQoNCmBgYHtyIG9wdGlvbnMtc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCm9wdGlvbnMoc2NpcGVuID0gOTk5KSAjLSBwYXJhIHF1aXRhciBsYSBub3RhY2nDs24gY2llbnTDrWZpY2ENCm9wdGlvbnMoInlhbWwuZXZhbC5leHByIiA9IFRSVUUpIA0KYGBgDQoNCg0KYGBge3Iga2xpcHB5LCBlY2hvID0gRkFMU0V9DQprbGlwcHk6OmtsaXBweShwb3NpdGlvbiA9IGMoInRvcCIsICJyaWdodCIpKSAjLSByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicmxlc3VyL2tsaXBweSIpDQpgYGANCg0KDQoNCjxociBjbGFzcz0ibGluZWEtYmxhY2siPg0KDQo8IS0tIEVsIHDDoXJyYWZvIGRlIGFiYWpvIGhhcyBkZSBkZWphcmxvIGNhc2kgaWd1YWwsIHNvbG8gSEFTIGRlIFNVU1RJVFVJUiAicGVyZXpwNDQiIHBvciB0dSB1c3VhcmlvIGRlIEdpdGh1Yi0tPg0KVHJhYmFqbyBlbGFib3JhZG8gcGFyYSBsYSBhc2lnbmF0dXJhICJQcm9ncmFtYWNpw7NuIHkgbWFuZWpvIGRlIGRhdG9zIGVuIGxhIGVyYSBkZWwgQmlnIERhdGEiIGRlIGxhIFVuaXZlcnNpdGF0IGRlIFZhbMOobmNpYSBkdXJhbnRlIGVsIGN1cnNvIDIwMjEtMjAyMi4gRWwgcmVwbyBkZWwgdHJhYmFqbyBlc3TDoSBbYXF1w61dKGh0dHBzOi8vZ2l0aHViLmNvbS9jYXlldGFubzEwOC90cmFiYWpvX0JpZ0RhdGFfZXF1aXBvKXt0YXJnZXQ9Il9ibGFuayJ9LiANCg0KPCEtLSBFbCBww6FycmFmbyBkZSBhYmFqbyBoYXMgZGUgZGVqYXJsbyBleGFjdGFtZW50ZSBpZ3VhbCwgTk8gaGFzIGRlIGNhbWJpYXIgbmFkYS0tPg0KDQpMYSBww6FnaW5hIHdlYiBkZSBsYSBhc2lnbmF0dXJhIHkgbG9zIHRyYWJham9zIGRlIG1pcyBjb21wYcOxZXJvcyBwdWVkZW4gdmVyc2UgW2FxdcOtXShodHRwczovL3BlcmV6cDQ0LmdpdGh1Yi5pby9pbnRyby1kcy0yMS0yMi13ZWIvMDctdHJhYmFqb3MuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4NCg0KPGhyIGNsYXNzPSJsaW5lYS1yZWQiPg0KDQojIExpYnJlcsOtYSBkZSBwYXF1ZXRlcw0KDQpgYGB7ciBwYWNrYWdlcy1zZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGtsaXBweSkgICMtIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJybGVzdXIva2xpcHB5IikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHJpbykNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2dhbmltYXRlKQ0KbGlicmFyeShnZ1RoZW1lQXNzaXN0KQ0KbGlicmFyeShnbG9iZTRyKSAgI3JlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJKb2huQ29lbmUvZ2xvYmU0ciIpDQpsaWJyYXJ5KHJlbW90ZXMpIA0KbGlicmFyeShndCkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHRyZWVtYXApICNpbnN0YWxsLnBhY2thZ2VzKHRyZWVtYXApDQpsaWJyYXJ5KGQzdHJlZVIpICNyZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiZDN0cmVlUi9kM3RyZWVSIikNCmBgYA0KDQojIENhbXBlw7NuIGRlbCBtdW5kbw0KDQpgYGB7cn0NCiMgYXF1aSBpcsOhIGZvdG8geSBjb3NpbGxhcyBkZWwgY2FtcGVvbiBkZSBlc3RlIGZpbmRlDQpgYGANCg0KDQoNCiMgSGlzdG9yaWEgZGUgbGEgRjENCg0KDQojIExPR09TIERFIExBIEZPUk1VTEEgMSAgey50YWJzZXR9DQoNCiMjIExvZ28gZGUgMTk4NSBhIDE5ODYNCg0KDQo8Y2VudGVyPg0KIVtMb2dvIGRlIDE5ODUgYSAxOTg2XSguL2ltYWdlbmVzL2xvZ29zLzE5ODUtMTk4Ni5wbmcpe3dpZHRoPTQwMCBoZWlnaHQ9NzB9DQo8L2NlbnRlcj4NCg0KDQoNCg0KDQoNCiMjIExvZ28gZGUgMTk4NyBhIDE5OTMNCjxjZW50ZXI+DQohW0xvZ28gZGUgMTk4NyBhIDE5OTNdKC4vaW1hZ2VuZXMvbG9nb3MvMTk4Ny0xOTkzLmpwZyl7d2lkdGg9MjUwIGhlaWdodD0zMDB9DQo8L2NlbnRlcj4NCg0KIyMgTG9nbyBkZSAxOTk0IGEgMjAxNw0KPGNlbnRlcj4NCiFbTG9nbyBkZSAxOTk0IGEgMjAxN10oLi9pbWFnZW5lcy9sb2dvcy8xOTk0LTIwMTcucG5nKXt3aWR0aD00NTAgaGVpZ2h0PTMwMH0NCjwvY2VudGVyPg0KIyMgTG9nbyBBY3R1YWwNCjxjZW50ZXI+DQohW0xPR08gZGVzZGUgMjAxOCBoYXN0YSBsYSBhY3R1YWxpZGFkXSguL2ltYWdlbmVzL2xvZ29zLzIwMTgtLnBuZyl7d2lkdGg9NDAwIGhlaWdodD0zMDB9DQo8L2NlbnRlcj4NCg0KDQojIENvY2hlcw0KPCEtLS0NCmFxdcOtIGludGVudGFyZW1vcyBtZXRlciBsYSB0cmFuc2ljaW9uIGRlIGltw6FlbmVzDQotLT4NCg0KDQojIGRhdG9zIFByb3RhZ29uaXN0YXMNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCiMtLS1QUkVQQVJBQ0lPTiBERSBMT1MgREFUT1MNCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KI3N0cihyZXN1bHRhZG9zKQ0KI3N0cihwaWxvdG9zKQ0KI3BpbG90b3NbLCBjKDEpXSA8LSBzYXBwbHkocGlsb3Rvc1ssIGMoMSldLCBhcy5udW1lcmljKQ0KI3Jlc3VsdGFkb3NbLCBjKDMsNiw5KV0gPC0gc2FwcGx5KHJlc3VsdGFkb3NbLCBjKDMsNiw5KV0sIGFzLm51bWVyaWMpDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojbnVtZXJvIGRlIGNhcnJlcmFzIHF1ZSBoYSBjb3JyaWRvIGNhZGEgcGlsb3RvDQoNCiNleHBsaWNhY2lvbiBkZSBsbyBxdWUgaGFnbywgbm8gc2UgcG9ycXVlIGxhIHZhcmlhYmxlIHN1bWF0b3JpbyBubyBsYSBkZXRlY3RhIGNvbW8gbnVtZXJpY2EgYXVucXVlIGxhIHBhc2UgYSBudW1lcmljYSwgcG9yIHRhbnRvIGFsIG9yZGVuYXIgY29uIHNsaWNlIG1heCBubyBmdW5jaW9uYSwgbG8gcXVlIGhlIGhlY2hvIGVzIHVzYXIgbGEgZnVuY2lvbiBhcnJhbmdlLCBxdWUgb3JkZW5hIGRlIG1lbm9yIGEgbWF5b3IsIHBlcm8gY29tbyBxdWVyZW1vcyBsb3MgcXVlIG1hcyBjYXJyZXJhcyBoYW4gY29ycmlkbywgbm8gbWUgc2lydmUgZGUgbWVub3IgYSBtYXlvciwgcG9yIHRhbnRvIGhlIG11bHRpcGxpY2FkbyBsYSB2YXJpYWJsZSBkZWwgc3VtYXRvcmlvIHBvciAtMSwgaGUgdXNhZG8gYXJyYW5nZSBwYXJhIHF1ZSBsb3MgcXVlIG3DoXMgY2FycmVyYXMgdGllbmVuIHNhbGdhbiBwcmltZXJvLCB5IGx1ZWdvIGhlIHZ1ZWx0byBhIG11bHRpcGxpY2FyIHBvciAtMS4gbHVlZ28gaGUgY29naWRvIG1heW9yZXMgZGUgMjAyIGNhcnJlcmFzLCBxdWUgc29uIGxvcyAyMCBxdWUgbcOhcyB0aWVuZW4sIHBvcnF1ZSBzaSBoYWdvIHNsaWNlIHNlIGRlc2N1YWRyYSB5IHRlIGRldnVlbHZlIGVsIGRmIGRlbCBwcmluY2lwaW8NCg0Kbl9jYXJyZXJhcyA8LSByZXN1bHRhZG9zICU+JSBncm91cF9ieShkcml2ZXJJZCkgJT4lIG11dGF0ZShudW1lcm9fY2FycmVyYXMgPSBzdW0obigpKSkgJT4lIGRpc3RpbmN0KG51bWVyb19jYXJyZXJhcykgJT4lIGFycmFuZ2UoZGVzYyhudW1lcm9fY2FycmVyYXMpKSAjbXV0YXRlKG51bWVyb19jYXJyZXJhc19maW5hbCA9IG51bWVyb19jYXJyZXJhcyotMSkNCg0Kbl9jYXJyZXJhc19ub20gPC0gZnVsbF9qb2luKG5fY2FycmVyYXMsIHBpbG90b3MsIGMgKCJkcml2ZXJJZCIgPSAiZHJpdmVySWQiKSkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBudW1lcm9fY2FycmVyYXMpICAlPiUgIGZpbHRlcihudW1lcm9fY2FycmVyYXMgPj0gMjAyICkgI2xvcyAyMCBxcXVlIG1hcyBjYXJyZXJhcyB0aWVuZW4gKG5vIGZ1bmNpb25hIHVzYXIgc2xpY2VfbWF4KQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBudW1lcm8gZGUgdmljdG9yaWFzIHBvciBwaWxvdG8NCnZpY3RvcmlhcyA8LSByZXN1bHRhZG9zICU+JSBmaWx0ZXIocG9zaXRpb24gPT0gIjEiKSAlPiUgZ3JvdXBfYnkoZHJpdmVySWQpICU+JSBtdXRhdGUobl92aWN0b3JpYXMgPSBzdW0obigpKSkgJT4lIGRpc3RpbmN0KG5fdmljdG9yaWFzKSAlPiUgYXJyYW5nZShkZXNjKG5fdmljdG9yaWFzKSkjbXV0YXRlKG5fdmljdG9yaWFzX2ZpbmFsID0gbl92aWN0b3JpYXMqLTEpDQoNCiNhcXVpIGZ1c2lvbm8gY29uIGVsIGRmIGRlIHBpbG90b3MgcGFyYSBxdWUgYXBhcmV6Y2EgZWwgbm9tYnJlIHkgbm8gc8OzbG8gZWwgSUQgZGVsIHBpbG90byBlbiBjdWVzdGlvbiwgeSBoYWdvIGxvIG1pc21vIHF1ZSBlbiBlbCBhcGFydGFkbyBkZSBhcnJpYmEgcGFyYSBvcmRlbmFyDQp2aWN0b3JpYXNfY29uX25vbWJyZSA8LSBmdWxsX2pvaW4odmljdG9yaWFzLCBwaWxvdG9zLCBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIG5hdGlvbmFsaXR5LCBkcml2ZXJSZWYsIG5fdmljdG9yaWFzKSAgI2xvcyAxMCBjb24gbWFzIHZpY3RvcmlhcywgdG1wIGZ1bmNpb25hIHNsaWNlX21heA0KbWFzX3ZpY3RvcmlhcyA8LSB2aWN0b3JpYXNfY29uX25vbWJyZSAlPiUgIGZpbHRlcihuX3ZpY3RvcmlhcyA+PSAyNSApIA0KDQoNCg0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojcmVzdWx0YWRvIG1lZGlvDQoNCnJlc3VsdGFkb3NbLCBjKDcpXSA8LSBzYXBwbHkocmVzdWx0YWRvc1ssIGMoNyldLCBhcy5udW1lcmljKQ0KcmVzdWx0YWRvc1tpcy5uYShyZXN1bHRhZG9zKV0gPC0gMjUgDQoNCnJlc3VsdGFkb19tZWRpbyA8LSAgZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsICBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgcG9zaXRpb24pICU+JSBncm91cF9ieShkcml2ZXJJZCkgJT4lIG11dGF0ZShyZXN1bHRfbWVkaW8gPSBtZWFuKHBvc2l0aW9uKSkgJT4lIGRpc3RpbmN0IChkcml2ZXJJZCwgZHJpdmVyUmVmLCByZXN1bHRfbWVkaW8pICU+JSBhcnJhbmdlKHJlc3VsdF9tZWRpbykNCg0KI3Jlc3VsdGFkbyBtZWRpbyBlbiBjbGFzaWZpY2FjaW9uDQpyZXN1bHRhZG9fbWVkaW9fY2xhcyA8LSAgZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsICBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgZ3JpZCkgJT4lIGdyb3VwX2J5KGRyaXZlcklkKSAlPiUgbXV0YXRlKHJlc3VsdF9tZWRpb19jbGFzID0gbWVhbihncmlkKSkgJT4lIGRpc3RpbmN0IChkcml2ZXJJZCwgZHJpdmVyUmVmLCByZXN1bHRfbWVkaW9fY2xhcykgICU+JSBmaWx0ZXIocmVzdWx0X21lZGlvX2NsYXMgPiAwKSAlPiUgYXJyYW5nZShyZXN1bHRfbWVkaW9fY2xhcykgIA0KDQoNCiNudW1lcm8gZGUgdnVlbHRhcyBsaWRlcmFuZG8NCg0KDQojcHVudG9zIHBvciBjYXJyZXJhIChwdW50b3MvY2FycmVyYSkNCg0KcHVudG9zX3hfY2FycmVyYSA8LSAgZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsICBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgcG9pbnRzKSAlPiUgZnVsbF9qb2luKC4sIG5fY2FycmVyYXMsICBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBncm91cF9ieShkcml2ZXJJZCkgJT4lIG11dGF0ZSh0b3RhbF9wdW50b3MgPSBzdW0ocG9pbnRzKSkgJT4lIGRpc3RpbmN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG51bWVyb19jYXJyZXJhcywgdG90YWxfcHVudG9zKSAlPiUgbXV0YXRlKG1lZGlhX3B1bnRvcyA9IHRvdGFsX3B1bnRvcy9udW1lcm9fY2FycmVyYXMpICU+JSBhcnJhbmdlKGRlc2MobWVkaWFfcHVudG9zKSkNCg0KYGBgDQoNCg0KIyBHcmFmaWNvIG3DoXMgdmljdG9yaWFzDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KDQojc2UgbmVjZXNpdGEgIm1hc192aWN0b3JpYXMiDQoNCiNoYXkgcXVlIGRhcmxlIGZvcm1hdG8geSBtaXJhciBsbyBkZSBhbmltYXJsbyBwb3IgZmVjaGENCg0KDQpnZ19tYXNfdmljdG9yaWFzIDwtIGdncGxvdChtYXNfdmljdG9yaWFzLCBhZXMoeCA9IHJlb3JkZXIoZHJpdmVyUmVmLCBuX3ZpY3RvcmlhcyksIHkgPSBuX3ZpY3RvcmlhcyApKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIGxhYnMoeCA9ICJQaWxvdG8iICwgeSA9ICJOw7ptZXJvIGRlIHZpY3RvcmlhcyIpDQpnZ19tYXNfdmljdG9yaWFzDQojdHJhYmFqbyAtLT4gZGFybGUgZm9ybWF0byBjaHVsbywgeWEgdmVyZW1vcyBlc3RlIHB1ZW50ZSBzaSBsZSBwb2RlbW9zIG1ldGVyIGRpbsOhbWljbyBvIHF1ZQ0KDQogICAgICAgICAgICAgICAgICAgICANCmBgYA0KDQoNCiMjIFBhcnJpbGxhIGRlIHBpbG90b3MgMjAyMSB0YWJsYQ0KDQpgYGB7cn0NCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KY2FycmVyYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3JhY2VzLmNzdiIpDQpsaWJyYXJ5KHN0cmluZ3IpDQoNCg0KcGlsb3Rvc18yMDIxIDwtIGZ1bGxfam9pbihjYXJyZXJhcywgcmVzdWx0YWRvcywgYygicmFjZUlkIiA9ICJyYWNlSWQiKSApICU+JSANCiAgZnVsbF9qb2luKC4scGlsb3RvcywgYygiZHJpdmVySWQiPSJkcml2ZXJJZCIpKSAlPiUgDQogIGZpbHRlcih5ZWFyPT0iMjAyMSIpICU+JSANCiAgc2VsZWN0KGZvcmVuYW1lLHN1cm5hbWUsIHllYXIpICU+JSBkaXN0aW5jdChmb3JlbmFtZSxzdXJuYW1lKSAlPiUgbmEub21pdCgpICU+JSBhcnJhbmdlKHN1cm5hbWUpICU+JSBzdHJfcmVwbGFjZV9hbGwoLiwgIsODwqkiLCAiw6kiKSAlPiUgc3RyX3JlcGxhY2VfYWxsKC4sICLDg8KkIiwgIsOkIikgJT4lIHN0cl9yZXBsYWNlX2FsbCguLCAiw4PCtiIsICLDtiIpDQoNCm5vbWJyZXNfbm9ybWFsZXMgPC0gYygiQWxvbnNvIiwgIkJvdHRhcyIsICJHYXNseSIsICJHaW92aW5henppIiwgIkhhbWlsdG9uIiwgIkxhdGlmaSIsICJMZWNsZXJjIiwgIk1hemVwaW4iLCAiTm9ycmlzIiwgIk9jb24iLCAiUMOpcmV6IiwgIlLDpGlra8O2bmVuIiwgIlJpY2NpYXJkbyIsICJSdXNzZWxsIiwgIlNhaW56IiwgIlNjaHVtYWNoZXIiLCAiU3Ryb2xsIiwgIlRzdW5vZGEiLCAiVmVyc3RhcHBlbiIsICJWZXR0ZWwiKQ0KDQpwaWxvdG9zXzIwMjEgPC0gIGZ1bGxfam9pbihjYXJyZXJhcywgcmVzdWx0YWRvcywgYygicmFjZUlkIiA9ICJyYWNlSWQiKSApICU+JSANCiAgZnVsbF9qb2luKC4scGlsb3RvcywgYygiZHJpdmVySWQiPSJkcml2ZXJJZCIpKSAlPiUgDQogIGZpbHRlcih5ZWFyPT0iMjAyMSIpICU+JSANCiAgc2VsZWN0KGZvcmVuYW1lLHN1cm5hbWUsIHllYXIpICU+JSBkaXN0aW5jdChmb3JlbmFtZSxzdXJuYW1lKSAlPiUgbmEub21pdCgpICU+JSBhcnJhbmdlKHN1cm5hbWUpICU+JSBhZGRfY29sdW1uKG5vbWJyZXNfbm9ybWFsZXMpICANCiANCg0KIyBQw4PCqXJleg0KIyBSw4PCpGlra8ODwrZuZW4NCmZvdG9zX3BpbF8yMDIxIDwtIGMoIi4vaW1hZ2VuZXMvcGlsb3Rvcy9hbG9uc28ucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9ib3R0YXMucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9nYXNseS5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL2dpb3ZpbmF6emkuanBnIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9oYW1pbHRvbi5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL2xhdGlmaS5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL2xlY2xlcmMucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy9tYXplcGluLnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3Mvbm9ycmlzLnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3Mvb2Nvbi5qcGciLCAiLi9pbWFnZW5lcy9waWxvdG9zL3BlcmV6LnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvcmFpa2tvbmVuLnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvcmljY2lhcmRvLnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvcnVzc2VsbC5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL3NhaW56LnBuZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvbWljay5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL3N0cm9sbC5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL3RzdW5vZGEucG5nIiwgIi4vaW1hZ2VuZXMvcGlsb3Rvcy92ZXJzdGFwcGVuLmpwZyIsICIuL2ltYWdlbmVzL3BpbG90b3MvdmV0dGVsLnBuZyIpDQoNCmZvdG9zX3BhaXNfMjAyMSA8LSBjKCIuL2ltYWdlbmVzL3BhaXNlcy9lc3BhbnlhLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy9maW5sYW5kaWEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2ZyYW5jaWEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2l0YWxpYS5wbmciLCIuL2ltYWdlbmVzL3BhaXNlcy91ay5wbmciLCAiLi9pbWFnZW5lcy9wYWlzZXMvY2FuYWRhLnBuZyIsIi4vaW1hZ2VuZXMvcGFpc2VzL21vbmFjby5wbmciLCAiLi9pbWFnZW5lcy9wYWlzZXMvcnVzaWEucG5nIiwiLi9pbWFnZW5lcy9wYWlzZXMvdWsucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2ZyYW5jaWEucG5nIiwiLi9pbWFnZW5lcy9wYWlzZXMvbWV4aWNvLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy9maW5sYW5kaWEucG5nIiwiLi9pbWFnZW5lcy9wYWlzZXMvYXVzdHJhbGlhLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy91ay5wbmciLCIuL2ltYWdlbmVzL3BhaXNlcy9lc3BhbnlhLnBuZyIsICIuL2ltYWdlbmVzL3BhaXNlcy9hbGVtYW5pYS5wbmciLCIuL2ltYWdlbmVzL3BhaXNlcy9jYW5hZGEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2phcG9uLnBuZyIsIi4vaW1hZ2VuZXMvcGFpc2VzL2hvbGFuZGEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL2FsZW1hbmlhLnBuZyIpDQoNCmZvdG9zX2VzY18yMDIxIDwtIGMoIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9hbHBpbmUucG5nIiwiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL21lcmNlZGVzLnBuZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9hbHBoYXRhdXJpLnBuZyIsICIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvYWxmYXJvbWVvLmpwZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9tZXJjZWRlcy5wbmciLCAiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL3dpbGxpYW1zLnBuZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9mZXJyYXJpLnBuZyIsICIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvaGFhcy5wbmciLCIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvbWNsYXJlbi5wbmciLCAiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL2FscGluZS5wbmciLCIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvcmVkYnVsbC5wbmciLCAiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL2FsZmFyb21lby5qcGciLCIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvbWNsYXJlbi5wbmciLCAiLi9pbWFnZW5lcy9lc2N1ZGVyaWFzL3dpbGxpYW1zLnBuZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9mZXJyYXJpLnBuZyIsICIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvaGFhcy5wbmciLCIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvYXN0b24ucG5nIiwgIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9hbHBoYXRhdXJpLnBuZyIsIi4vaW1hZ2VuZXMvZXNjdWRlcmlhcy9yZWRidWxsLnBuZyIsICIuL2ltYWdlbmVzL2VzY3VkZXJpYXMvYXN0b24ucG5nIikNCg0KcGlsb3Rvc18yMDIxIDwtIHBpbG90b3NfMjAyMSAlPiUNCiAgYWRkX2NvbHVtbihmb3Rvc19waWxfMjAyMSwgZm90b3NfcGFpc18yMDIxLCBmb3Rvc19lc2NfMjAyMSkgJT4lIHNlbGVjdChub21icmVzX25vcm1hbGVzLCBmb3Rvc19waWxfMjAyMSwgZm90b3NfcGFpc18yMDIxLCBmb3Rvc19lc2NfMjAyMSkNCg0KbGlicmFyeShndCkNCm11bmRpYWxfMjAyMSA8LSBwaWxvdG9zXzIwMjEgJT4lIGd0KCkgJT4lIHRleHRfdHJhbnNmb3JtKCBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKGZvdG9zX3BpbF8yMDIxKSksIGZuID0gZnVuY3Rpb24oeCkge2d0Ojpsb2NhbF9pbWFnZSh4LCBoZWlnaHQgPSA4MCl9KSAlPiUgdGV4dF90cmFuc2Zvcm0oIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoZm90b3NfcGFpc18yMDIxKSksIGZuID0gZnVuY3Rpb24oeCkge2d0Ojpsb2NhbF9pbWFnZSh4LCBoZWlnaHQgPSA4MCl9KSAlPiUgdGV4dF90cmFuc2Zvcm0oIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoZm90b3NfZXNjXzIwMjEpKSwgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OmxvY2FsX2ltYWdlKHgsIGhlaWdodCA9IDgwKX0pICU+JSB0YWJfaGVhZGVyKHRpdGxlID0gbWQoIioqUGlsb3RvcyAyMDIxKioiKSwgc3VidGl0bGUgPSBtZCgiUGFycmlsbGEiKSkgJT4lICAgY29sc19sYWJlbCgNCiAgICBub21icmVzX25vcm1hbGVzID0gaHRtbCgiIiksDQogICAgZm90b3NfcGlsXzIwMjEgPSBodG1sKCIiKSwNCiAgICBmb3Rvc19wYWlzXzIwMjEgPSBodG1sKCIiKSwNCiAgICBmb3Rvc19lc2NfMjAyMSA9IGh0bWwoIiIpKSAlPiUgIA0KICB0YWJfb3B0aW9ucyh0YWJsZS5iYWNrZ3JvdW5kLmNvbG9yID0gImdyYXkxMyIsICAgdGFibGUuZm9udC5jb2xvci5saWdodCA9ICJjeWFuIikgJT4lIA0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIsDQogIGNvbHVtbnMgPSBldmVyeXRoaW5nKCkpDQoNCg0KbXVuZGlhbF8yMDIxDQpgYGANCg0KDQojIyBFc3Bhw7FvbGVzIHBvciBsYSBGMQ0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiNwaWxvdG9zIGVzcGHDsW9sZXMNCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KDQpwaWxvdG9zX2VzcCA8LSBwaWxvdG9zICU+JSBmaWx0ZXIobmF0aW9uYWxpdHkgPT0gIlNwYW5pc2giKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG5hdGlvbmFsaXR5KSANCg0KDQojbWFzIHZpY3RvcmlhcyBkZSBwaWxvdG9zIGVzcGHDsW9sZXMNCm1hc192aWN0b3JpYXNfZXNwIDwtIGZ1bGxfam9pbih2aWN0b3JpYXNfY29uX25vbWJyZSwgcGlsb3RvcywgYyAoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgZmlsdGVyKG5hdGlvbmFsaXR5LnggPT0gIlNwYW5pc2giKSAlPiUgIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLngsIG5fdmljdG9yaWFzLCBuYXRpb25hbGl0eS54KSANCg0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KYGBgDQoNCg0KDQojIyBFc2N1ZGVyw61hcyBjYW1wZW9uYXMgey50YWJzZXR9DQoNCiMjIyBQb3IgdGFtYcOxbw0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRSwgaW5jbHVkZSA9IEZBTFNFfQ0KI2RhdG9zIGRlIGVzY3VkZXJpYXMgcGEgcXVpZW4gcXVpZXJhIGhhY2VyIGFsZ28NCmVzY3VkZXJpYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9ycy5jc3YiKQ0KZXNjdWRlcmlhczIgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9yX3N0YW5kaW5ncy5jc3YiKQ0KcmVzdWx0X2VzY3VkZXJpYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9yX3Jlc3VsdHMuY3N2IikNCg0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KY2FycmVyYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3JhY2VzLmNzdiIpDQojZXNjdWRlcmlhc2VzcCA8LSBlc2N1ZGVyaWFzICU+JSBmaWx0ZXIobmF0aW9uYWxpdHkgPT0gIlNwYW5pc2giKSAjZXNjdWRlcmlhcyBlc3Bhw7FvbGFzDQoNCmNhbXBlb25lc19lc2MgPC0gZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsIGMoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgZnVsbF9qb2luKC4sIGNhcnJlcmFzLCBjKCJyYWNlSWQiID0gInJhY2VJZCIpKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG5hdGlvbmFsaXR5LCBjb25zdHJ1Y3RvcklkLCBwb2ludHMsIHllYXIsIHJvdW5kKSAlPiUgZnVsbF9qb2luKC4sIGVzY3VkZXJpYXMsIGMoImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiKSkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBuYXRpb25hbGl0eS54LCBjb25zdHJ1Y3RvcklkLCBwb2ludHMsIHllYXIsIG5hbWUsIHJvdW5kKSAlPiUgIGdyb3VwX2J5KHllYXIsIGRyaXZlclJlZikgJT4lICBtdXRhdGUocHVudG9zX3RvdGFsZXMgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKSAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lIHNsaWNlX21heChwdW50b3NfdG90YWxlcywgbj0xKSAlPiUgc2VsZWN0KG5hbWUsIGRyaXZlclJlZikgJT4lIGdyb3VwX2J5KG5hbWUsIGRyaXZlclJlZikgJT4lIG11dGF0ZSh0b3RhbF9jYW1wID0gc3VtKCBOTiA9IG4oKSkpICU+JSBhcnJhbmdlKG5hbWUpIA0KDQoNCmNhbXBlb25lc19lc2MgPC0gY2FtcGVvbmVzX2VzY1shKGNhbXBlb25lc19lc2MkZHJpdmVyUmVmID09ICdtYXhfdmVyc3RhcHBlbicpLF0gDQoNCmxpYnJhcnkodHJlZW1hcCkNCmxpYnJhcnkoZDN0cmVlUikNCg0KDQojIGJhc2ljIHRyZWVtYXANCmdnX2VzY19jYW1wZW9uZXMgPC0gdHJlZW1hcChjYW1wZW9uZXNfZXNjLA0KICAgICAgICAgICAgaW5kZXg9YygibmFtZSIsImRyaXZlclJlZiIpLA0KICAgICAgICAgICAgdlNpemU9InRvdGFsX2NhbXAiLA0KICAgICAgICAgICAgdHlwZT0iaW5kZXgiLA0KICAgICAgICAgICAgdkNvbG9yID0gIm5hbWUiLA0KICAgICAgICAgICAgZm9udHNpemUubGFiZWxzPWMoMTUsMjApLA0KICAgICAgICAgICAgYmcubGFiZWxzPWMoInRyYW5zcGFyZW50IiksDQogICAgICAgICAgICBwYWxldHRlID0gIlNldDIiLA0KICAgICAgICAgICAgYWxpZ24ubGFiZWxzPWxpc3QoDQogICAgICAgICAgICAgIGMoImNlbnRlciIsICJjZW50ZXIiKSwgDQogICAgICAgICAgICAgIGMoImNlbnRlciIsICJib3R0b20iKSksDQogICAgICAgICAgICB0aXRsZSA9ICJFc2N1ZGVyw61hcyBjb24gbcOhcyBjYW1wZW9uZXMiLA0KICAgICAgICAgICAgdGl0bGUubGVnZW5kID0gIkVzY3VkZXLDrWFzIikgICANCg0KYGBgDQoNCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCiNkYXRvcyBkZSBlc2N1ZGVyaWFzIHBhIHF1aWVuIHF1aWVyYSBoYWNlciBhbGdvDQojZXNjdWRlcmlhcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvY29uc3RydWN0b3JzLmNzdiIpDQojZXNjdWRlcmlhczIgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9yX3N0YW5kaW5ncy5jc3YiKQ0KI3Jlc3VsdF9lc2N1ZGVyaWFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9jb25zdHJ1Y3Rvcl9yZXN1bHRzLmNzdiIpDQoNCiNwaWxvdG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9kcml2ZXJzLmNzdiIpDQojcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KI2NhcnJlcmFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yYWNlcy5jc3YiKQ0KI2VzY3VkZXJpYXNlc3AgPC0gZXNjdWRlcmlhcyAlPiUgZmlsdGVyKG5hdGlvbmFsaXR5ID09ICJTcGFuaXNoIikgI2VzY3VkZXJpYXMgZXNwYcOxb2xhcw0KDQojY2FtcGVvbmVzX2VzYyA8LSBmdWxsX2pvaW4ocGlsb3RvcywgcmVzdWx0YWRvcywgYygiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBmdWxsX2pvaW4oLiwgY2FycmVyYXMsIGMoInJhY2VJZCIgPSAicmFjZUlkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgbmF0aW9uYWxpdHksIGNvbnN0cnVjdG9ySWQsIHBvaW50cywgeWVhciwgcm91bmQpICU+JSBmdWxsX2pvaW4oLiwgZXNjdWRlcmlhcywgYygiY29uc3RydWN0b3JJZCIgPSAiY29uc3RydWN0b3JJZCIpKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG5hdGlvbmFsaXR5LngsIGNvbnN0cnVjdG9ySWQsIHBvaW50cywgeWVhciwgbmFtZSwgcm91bmQpICU+JSAgZ3JvdXBfYnkoeWVhciwgZHJpdmVyUmVmKSAlPiUgIG11dGF0ZShwdW50b3NfdG90YWxlcyA9IGN1bXN1bShwb2ludHMpKSAlPiUgdW5ncm91cCgpICU+JSBncm91cF9ieSh5ZWFyKSAlPiUgc2xpY2VfbWF4KHB1bnRvc190b3RhbGVzLCBuPTEpICU+JSBzZWxlY3QobmFtZSwgZHJpdmVyUmVmKSAlPiUgZ3JvdXBfYnkobmFtZSwgZHJpdmVyUmVmKSAlPiUgbXV0YXRlKHRvdGFsX2NhbXAgPSBzdW0oIE5OID0gbigpKSkgJT4lIGFycmFuZ2UobmFtZSkgDQoNCg0KI2NhbXBlb25lc19lc2MgPC0gY2FtcGVvbmVzX2VzY1shKGNhbXBlb25lc19lc2MkZHJpdmVyUmVmID09ICdtYXhfdmVyc3RhcHBlbicpLF0gDQoNCiNsaWJyYXJ5KHRyZWVtYXApDQojbGlicmFyeShkM3RyZWVSKQ0KDQoNCiMgYmFzaWMgdHJlZW1hcA0KI2dnX2VzY19jYW1wZW9uZXMgPC0gdHJlZW1hcChjYW1wZW9uZXNfZXNjLA0KICAgICAgICAgICAgI2luZGV4PWMoIm5hbWUiLCJkcml2ZXJSZWYiKSwNCiAgICAgICAgICAgICN2U2l6ZT0idG90YWxfY2FtcCIsDQogICAgICAgICAgICAjdHlwZT0iaW5kZXgiLA0KICAgICAgICAgICAgI3ZDb2xvciA9ICJuYW1lIiwNCiAgICAgICAgICAgICNmb250c2l6ZS5sYWJlbHM9YygyNSwxNyksDQogICAgICAgICAgICAjYmcubGFiZWxzPWMoInRyYW5zcGFyZW50IiksDQogICAgICAgICAgICAjcGFsZXR0ZSA9ICJTZXQyIiwNCiAgICAgICAgICAgICNhbGlnbi5sYWJlbHM9bGlzdCgNCiAgICAgICAgICAgICAgI2MoImNlbnRlciIsICJjZW50ZXIiKSwgDQogICAgICAgICAgICAgICNjKCJjZW50ZXIiLCAiYm90dG9tIikpLA0KICAgICAgICAgICAgI3RpdGxlID0gIkVzY3VkZXLDrWFzIGNvbiBtw6FzIGNhbXBlb25lcyIsDQogICAgICAgICAgICAjdGl0bGUubGVnZW5kID0gIkVzY3VkZXLDrWFzIikgICANCg0KYGBgDQoNCmBgYHtyLCBmaWcuYWxpZ249J2NlbnRlcid9DQoNCmludGVyX2NhbXAgPC0gZDN0cmVlMihnZ19lc2NfY2FtcGVvbmVzICwgIHJvb3RuYW1lID0gIkVzY3VkZXLDrWFzIHkgQ2FtcGVvbmVzIikNCmludGVyX2NhbXANCg0KDQpgYGANCg0KIyMjIEVuIHZhbG9yZXMgYWJzb2x1dG9zDQoNCmBgYHtyfQ0KDQpjYW1wZW9uZXNfZXNjIDwtIGZ1bGxfam9pbihwaWxvdG9zLCByZXN1bHRhZG9zLCBjKCJkcml2ZXJJZCIgPSAiZHJpdmVySWQiKSkgJT4lIGZ1bGxfam9pbiguLCBjYXJyZXJhcywgYygicmFjZUlkIiA9ICJyYWNlSWQiKSkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBuYXRpb25hbGl0eSwgY29uc3RydWN0b3JJZCwgcG9pbnRzLCB5ZWFyLCByb3VuZCkgJT4lIGZ1bGxfam9pbiguLCBlc2N1ZGVyaWFzLCBjKCJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIikpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgbmF0aW9uYWxpdHkueCwgY29uc3RydWN0b3JJZCwgcG9pbnRzLCB5ZWFyLCBuYW1lLCByb3VuZCkgJT4lICBncm91cF9ieSh5ZWFyLCBkcml2ZXJSZWYpICU+JSAgbXV0YXRlKHB1bnRvc190b3RhbGVzID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkgJT4lIGdyb3VwX2J5KHllYXIpICU+JSBzbGljZV9tYXgocHVudG9zX3RvdGFsZXMsIG49MSkgJT4lIHVuZ3JvdXAoKSAlPiUgY291bnQobmFtZSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkNCg0KDQpnZ3Bsb3QoY2FtcGVvbmVzX2VzYywgYWVzKHggPSByZW9yZGVyKG5hbWUsbikseSA9IG4pKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCg0KDQojIEFsb25zbyAoZWwgbmFubykNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQojYWxvbnNvIHZzIGNvbXBhw7Flcm9zIGRlIGVxdWlwbw0KDQpwaWxvdG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9kcml2ZXJzLmNzdiIpDQpyZXN1bHRhZG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yZXN1bHRzLmNzdiIpDQplc2N1ZGVyaWFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9jb25zdHJ1Y3RvcnMuY3N2IikNCmNhcnJlcmFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yYWNlcy5jc3YiKQ0KDQphbG92c2FsbCA8LSBmdWxsX2pvaW4ocGlsb3RvcywgcmVzdWx0YWRvcywgYyAoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgIHNlbGVjdChkcml2ZXJSZWYsIHJlc3VsdElkLCByYWNlSWQsIGNvbnN0cnVjdG9ySWQsIHBvc2l0aW9uLCBwb2ludHMpICU+JSBmdWxsX2pvaW4oLiwgZXNjdWRlcmlhcywgYyAoImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiKSkgJT4lIHNlbGVjdChkcml2ZXJSZWYsIHJlc3VsdElkLCByYWNlSWQsIGNvbnN0cnVjdG9ySWQsIHBvc2l0aW9uLCBwb3NpdGlvbiwgcG9pbnRzLCBuYW1lKSAlPiUgZnVsbF9qb2luKC4sIGNhcnJlcmFzLCBjICgicmFjZUlkIiA9ICJyYWNlSWQiKSkgJT4lIHNlbGVjdChkcml2ZXJSZWYsIHJlc3VsdElkLCByYWNlSWQsIGNvbnN0cnVjdG9ySWQsIHBvc2l0aW9uLCBwb3NpdGlvbiwgcG9pbnRzLCBuYW1lLngsIHllYXIsIHJvdW5kKQ0KDQojYWxvX3ZzX21hcnF1ZXMgPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyID09IDIwMDEsIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJtYXJxdWVzIiksIHJvdW5kIDw9IDE0KQ0KDQphbG9fdnNfdHJ1bGxpIDwtIGFsb3ZzYWxsICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwMywgMjAwNCksIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJ0cnVsbGkiKSkgJT4lIHNsaWNlKDE6MTUsIDE3OjY3KSAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkNCg0KYWxvX3ZzX2Zpc2ljaGVsbGEgPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyICVpbiUgYygyMDA1LCAyMDA2KSwgZHJpdmVyUmVmICVpbiUgYygiYWxvbnNvIiwgImZpc2ljaGVsbGEiKSkgICU+JSBncm91cF9ieShkcml2ZXJSZWYsIHllYXIpICU+JSBtdXRhdGUocHVudG9zX2FjdW11bGFkb3MgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKQ0KDQphbG9fdnNfaGFtaWx0b24gPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyICVpbiUgYygyMDA3KSAsZHJpdmVyUmVmICVpbiUgYygiYWxvbnNvIiwgImhhbWlsdG9uIikpICAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkNCg0KYWxvX3ZzX3BpcXVldCA8LSBhbG92c2FsbCAlPiUgZmlsdGVyKHllYXIgJWluJSBjKDIwMDgsIDIwMDkpLCBkcml2ZXJSZWYgJWluJSBjKCJhbG9uc28iLCAicGlxdWV0X2pyIikpICU+JSBzbGljZSgxOjI4LCAzNjo2MykgJT4lIGdyb3VwX2J5KGRyaXZlclJlZiwgeWVhcikgJT4lIG11dGF0ZShwdW50b3NfYWN1bXVsYWRvcyA9IGN1bXN1bShwb2ludHMpKSAlPiUgdW5ncm91cCgpDQoNCiNhbG9fdnNfZ3Jvc2plYW4gPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyID09IDIwMDksIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJncm9zamVhbiIpLCByb3VuZCA+PSAxMSkNCg0KYWxvX3ZzX21hc3NhIDwtIGFsb3ZzYWxsICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAxMCwgMjAxMSwgMjAxMyksIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJtYXNzYSIpKSAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkNCg0KYWxvX3ZzX3JhaWtrb25lbiA8LSBhbG92c2FsbCAlPiUgZmlsdGVyKHllYXIgPT0gMjAxNCwgZHJpdmVyUmVmICVpbiUgYygiYWxvbnNvIiwgInJhaWtrb25lbiIpKSAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpICU+JSB1bmdyb3VwKCkNCg0KYWxvX3ZzX2J1dHRvbiA8LSBhbG92c2FsbCAlPiUgZmlsdGVyKHllYXIgJWluJSBjKDIwMTUsIDIwMTYpLCBkcml2ZXJSZWYgJWluJSBjKCJhbG9uc28iLCAiYnV0dG9uIikpICU+JSBncm91cF9ieShkcml2ZXJSZWYsIHllYXIpICU+JSBtdXRhdGUocHVudG9zX2FjdW11bGFkb3MgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKQ0KDQphbG9fdnNfdmFuZG9vcm5lIDwtIGFsb3ZzYWxsICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAxNywgMjAxOCksIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJ2YW5kb29ybmUiKSkgJT4lIHNsaWNlKDE6NDUsIDQ3OjgxKSAlPiUgZ3JvdXBfYnkoZHJpdmVyUmVmLCB5ZWFyKSAlPiUgbXV0YXRlKHB1bnRvc19hY3VtdWxhZG9zID0gY3Vtc3VtKHBvaW50cykpJT4lIHVuZ3JvdXAoKSANCg0KYWxvX3ZzX29jb24gPC0gYWxvdnNhbGwgJT4lIGZpbHRlcih5ZWFyID09IDIwMjEsIGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJvY29uIikpICU+JSBncm91cF9ieShkcml2ZXJSZWYsIHllYXIpICU+JSBtdXRhdGUocHVudG9zX2FjdW11bGFkb3MgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKQ0KDQpBTE9fVlNfQUxMIDwtIGZ1bGxfam9pbihhbG9fdnNfdHJ1bGxpLCBhbG9fdnNfZmlzaWNoZWxsYSwgYygiZHJpdmVyUmVmIj0gImRyaXZlclJlZiIsICJyZXN1bHRJZCIgPSAicmVzdWx0SWQiLCAicmFjZUlkIiA9ICJyYWNlSWQiLCAiY29uc3RydWN0b3JJZCIgPSAiY29uc3RydWN0b3JJZCIsICJwb3NpdGlvbiIgPSAicG9zaXRpb24iLCAicG9pbnRzIiA9ICJwb2ludHMiLCAibmFtZS54IiA9ICJuYW1lLngiLCAieWVhciIgPSAieWVhciIsICJyb3VuZCIgPSAicm91bmQiICwgInB1bnRvc19hY3VtdWxhZG9zIiA9ICJwdW50b3NfYWN1bXVsYWRvcyIpKSAlPiUgDQogIGZ1bGxfam9pbiguLCBhbG9fdnNfaGFtaWx0b24sIGMoImRyaXZlclJlZiI9ICJkcml2ZXJSZWYiLCAicmVzdWx0SWQiID0gInJlc3VsdElkIiwgInJhY2VJZCIgPSAicmFjZUlkIiwgImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiLCAicG9zaXRpb24iID0gInBvc2l0aW9uIiwgInBvaW50cyIgPSAicG9pbnRzIiwgIm5hbWUueCIgPSAibmFtZS54IiwgInllYXIiID0gInllYXIiLCAicm91bmQiID0gInJvdW5kIiwgInB1bnRvc19hY3VtdWxhZG9zIiA9ICJwdW50b3NfYWN1bXVsYWRvcyIpKSAlPiUgDQogIGZ1bGxfam9pbiguLCBhbG9fdnNfcGlxdWV0LCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIiwgInJlc3VsdElkIiA9ICJyZXN1bHRJZCIsICJyYWNlSWQiID0gInJhY2VJZCIsICJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIiwgInBvc2l0aW9uIiA9ICJwb3NpdGlvbiIsICJwb2ludHMiID0gInBvaW50cyIsICJuYW1lLngiID0gIm5hbWUueCIsICJ5ZWFyIiA9ICJ5ZWFyIiwgInJvdW5kIiA9ICJyb3VuZCIsICJwdW50b3NfYWN1bXVsYWRvcyIgPSAicHVudG9zX2FjdW11bGFkb3MiKSkgJT4lIA0KICBmdWxsX2pvaW4oLiwgYWxvX3ZzX21hc3NhLCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIiwgInJlc3VsdElkIiA9ICJyZXN1bHRJZCIsICJyYWNlSWQiID0gInJhY2VJZCIsICJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIiwgInBvc2l0aW9uIiA9ICJwb3NpdGlvbiIsICJwb2ludHMiID0gInBvaW50cyIsICJuYW1lLngiID0gIm5hbWUueCIsICJ5ZWFyIiA9ICJ5ZWFyIiwgInJvdW5kIiA9ICJyb3VuZCIsICJwdW50b3NfYWN1bXVsYWRvcyIgPSAicHVudG9zX2FjdW11bGFkb3MiKSkgICU+JSANCiAgZnVsbF9qb2luKC4sIGFsb192c19yYWlra29uZW4sIGMoImRyaXZlclJlZiI9ICJkcml2ZXJSZWYiLCAicmVzdWx0SWQiID0gInJlc3VsdElkIiwgInJhY2VJZCIgPSAicmFjZUlkIiwgImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiLCAicG9zaXRpb24iID0gInBvc2l0aW9uIiwgInBvaW50cyIgPSAicG9pbnRzIiwgIm5hbWUueCIgPSAibmFtZS54IiwgInllYXIiID0gInllYXIiLCAicm91bmQiID0gInJvdW5kIiwgInB1bnRvc19hY3VtdWxhZG9zIiA9ICJwdW50b3NfYWN1bXVsYWRvcyIpKSAlPiUgDQogIGZ1bGxfam9pbiguLCBhbG9fdnNfYnV0dG9uLCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIiwgInJlc3VsdElkIiA9ICJyZXN1bHRJZCIsICJyYWNlSWQiID0gInJhY2VJZCIsICJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIiwgInBvc2l0aW9uIiA9ICJwb3NpdGlvbiIsICJwb2ludHMiID0gInBvaW50cyIsICJuYW1lLngiID0gIm5hbWUueCIsICJ5ZWFyIiA9ICJ5ZWFyIiwgInJvdW5kIiA9ICJyb3VuZCIsICJwdW50b3NfYWN1bXVsYWRvcyIgPSAicHVudG9zX2FjdW11bGFkb3MiKSkgJT4lIA0KICBmdWxsX2pvaW4oLiwgYWxvX3ZzX3ZhbmRvb3JuZSwgYygiZHJpdmVyUmVmIj0gImRyaXZlclJlZiIsICJyZXN1bHRJZCIgPSAicmVzdWx0SWQiLCAicmFjZUlkIiA9ICJyYWNlSWQiLCAiY29uc3RydWN0b3JJZCIgPSAiY29uc3RydWN0b3JJZCIsICJwb3NpdGlvbiIgPSAicG9zaXRpb24iLCAicG9pbnRzIiA9ICJwb2ludHMiLCAibmFtZS54IiA9ICJuYW1lLngiLCAieWVhciIgPSAieWVhciIsICJyb3VuZCIgPSAicm91bmQiLCAicHVudG9zX2FjdW11bGFkb3MiID0gInB1bnRvc19hY3VtdWxhZG9zIikpICU+JSANCiAgZnVsbF9qb2luKC4sIGFsb192c19vY29uLCBjKCJkcml2ZXJSZWYiPSAiZHJpdmVyUmVmIiwgInJlc3VsdElkIiA9ICJyZXN1bHRJZCIsICJyYWNlSWQiID0gInJhY2VJZCIsICJjb25zdHJ1Y3RvcklkIiA9ICJjb25zdHJ1Y3RvcklkIiwgInBvc2l0aW9uIiA9ICJwb3NpdGlvbiIsICJwb2ludHMiID0gInBvaW50cyIsICJuYW1lLngiID0gIm5hbWUueCIsICJ5ZWFyIiA9ICJ5ZWFyIiwgInJvdW5kIiA9ICJyb3VuZCIsICJwdW50b3NfYWN1bXVsYWRvcyIgPSAicHVudG9zX2FjdW11bGFkb3MiKSkNCg0Kb2JqZXRvc19ub19ib3JyYXIgPC0gYygiQUxPX1ZTX0FMTCIsICJuX2NhcnJlcmFzX25vbSIsICJ2aWN0b3JpYXNfY29uX25vbWJyZSIpDQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIG9iamV0b3Nfbm9fYm9ycmFyXSkNCg0KDQpnYygpICNpbnN0cnVjY2lvbiBwYXJhIHF1ZSBjYXJndWUgZWwgZ3JhZmljbywgYWwgc2VyIHRhbiBjb21wbGVqbyBkYSBlcnJvciBkZSBubyBzw6kgcXXDqSBwZXJvIGNvbiBlc3RvIGZ1bmNpb25hDQpnZ2Fsb192c19hbGwgPC0gZ2dwbG90KGRhdGEgPSBBTE9fVlNfQUxMLCBhZXMocm91bmQsIHB1bnRvc19hY3VtdWxhZG9zLCBjb2xvciA9IGRyaXZlclJlZikpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKyANCiAgbGFicyh0aXRsZSA9ICJBbG9uc28gY29udHJhIGVsIG11bmRvIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJsZSBkYXMgdW4gY2FydG9uIGNvbiBydWVkYXMgeSBhw7puIHRlIHNhY2EgcHVudG9zIiwNCiAgICAgICB5ID0gIlB1bnRvcyIsIHggPSAiIikgKyBmYWNldF93cmFwKCB+IHllYXIpICsgdHJhbnNpdGlvbl9yZXZlYWwocm91bmQpDQoNCiNnZ2Fsb192c19hbGwNCg0KDQpgYGANCg0KIyBDYW1wZW9uZXMgZGVsIG11bmRvDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCnBpbG90b3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2RyaXZlcnMuY3N2IikNCnJlc3VsdGFkb3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3Jlc3VsdHMuY3N2IikNCmVzY3VkZXJpYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NvbnN0cnVjdG9ycy5jc3YiKQ0KY2FycmVyYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3JhY2VzLmNzdiIpDQoNCg0KDQpjYW1wZW9uZXMgPC0gZnVsbF9qb2luKHBpbG90b3MsIHJlc3VsdGFkb3MsIGMoImRyaXZlcklkIiA9ICJkcml2ZXJJZCIpKSAlPiUgZnVsbF9qb2luKC4sIGNhcnJlcmFzLCBjKCJyYWNlSWQiID0gInJhY2VJZCIpKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsIG5hdGlvbmFsaXR5LCBjb25zdHJ1Y3RvcklkLCBwb2ludHMsIHllYXIsIHJvdW5kKSAlPiUgZnVsbF9qb2luKC4sIGVzY3VkZXJpYXMsIGMoImNvbnN0cnVjdG9ySWQiID0gImNvbnN0cnVjdG9ySWQiKSkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBuYXRpb25hbGl0eS54LCBjb25zdHJ1Y3RvcklkLCBwb2ludHMsIHllYXIsIG5hbWUsIHJvdW5kKSAlPiUgIGdyb3VwX2J5KHllYXIsIGRyaXZlclJlZikgJT4lICBtdXRhdGUocHVudG9zX3RvdGFsZXMgPSBjdW1zdW0ocG9pbnRzKSkgJT4lIHVuZ3JvdXAoKSAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lIHNsaWNlX21heChwdW50b3NfdG90YWxlcywgbj0xKSAlPiUgdW5ncm91cCgpICU+JSBncm91cF9ieShkcml2ZXJSZWYpJT4lIG11dGF0ZSh0b3RhbF9jYW1wZW9uYXRvcyA9IHN1bShOTiA9IG4oKSkpICU+JSBkaXN0aW5jdChkcml2ZXJSZWYsIG5hdGlvbmFsaXR5LngsIHRvdGFsX2NhbXBlb25hdG9zKSAlPiUgYXJyYW5nZShuYXRpb25hbGl0eS54LCB0b3RhbF9jYW1wZW9uYXRvcykNCiAgDQpjYW1wZW9uZXMgPC0gY2FtcGVvbmVzWyEoY2FtcGVvbmVzJGRyaXZlclJlZiA9PSAnbWF4IHZlcnN0YXBwZW4nKSxdDQppZCA8LSByb3duYW1lcyhjYW1wZW9uZXMpDQpjYW1wZW9uZXMgPC0gY2JpbmQoaWQ9aWQsIGNhbXBlb25lcykNCmNhbXBlb25lc1ssIGMoMSldIDwtIHNhcHBseShjYW1wZW9uZXNbLCBjKDEpXSwgYXMubnVtZXJpYykNCg0KDQoNCg0KbGFiZWxfY2FtcGVvbmVzIDwtIGNhbXBlb25lcw0KbnVtYmVyX29mX2JhciA8LSBucm93KGxhYmVsX2NhbXBlb25lcykNCg0KYW5nbGUgPC0gOTAgLSAzNjAgKiAobGFiZWxfY2FtcGVvbmVzJGlkLTAuNSkgL251bWJlcl9vZl9iYXIgICAgICMgSSBzdWJzdHJhY3QgMC41IGJlY2F1c2UgdGhlIGxldHRlciBtdXN0IGhhdmUgdGhlIGFuZ2xlIG9mIHRoZSBjZW50ZXIgb2YgdGhlIGJhcnMuIE5vdCBleHRyZW1lIHJpZ2h0KDEpIG9yIGV4dHJlbWUgbGVmdCAoMCkNCmxhYmVsX2NhbXBlb25lcyRoanVzdCA8LSBpZmVsc2UoIGFuZ2xlIDwgLTkwLCAxLCAwKQ0KbGFiZWxfY2FtcGVvbmVzJGFuZ2xlIDwtIGlmZWxzZShhbmdsZSA8IC05MCwgYW5nbGUrMTgwLCBhbmdsZSkNCg0KDQoNCmJhc2VfY2FtcGVvbmVzIDwtIGNhbXBlb25lcyAlPiUgDQogIGdyb3VwX2J5KG5hdGlvbmFsaXR5LngpICU+JSANCiAgc3VtbWFyaXNlKHN0YXJ0PW1pbihpZCksIGVuZD1tYXgoaWQpKSAlPiUgDQogIHJvd3dpc2UoKSAlPiUgDQogIG11dGF0ZSh0aXRsZT1tZWFuKGMoc3RhcnQsIGVuZCkpKQ0KDQpncmlkX2NhbXBlb25lcyA8LSBiYXNlX2NhbXBlb25lcw0KZ3JpZF9jYW1wZW9uZXMkZW5kIDwtIGdyaWRfY2FtcGVvbmVzJGVuZFsgYyggbnJvdyhncmlkX2NhbXBlb25lcyksIDE6bnJvdyhncmlkX2NhbXBlb25lcyktMSldICsgMQ0KZ3JpZF9jYW1wZW9uZXMkc3RhcnQgPC0gZ3JpZF9jYW1wZW9uZXMkc3RhcnQgLSAxDQpncmlkX2NhbXBlb25lcyA8LSBncmlkX2NhbXBlb25lc1stMSxdDQoNCmdnX2NpcmNfdmljdG9yaWFzIDwtIGdncGxvdChjYW1wZW9uZXMsIGFlcyh4PWFzLmZhY3Rvcih5ZWFyKSwgeT10b3RhbF9jYW1wZW9uYXRvcywgZmlsbD1uYXRpb25hbGl0eS54LCBjb2xvciA9IG5hdGlvbmFsaXR5LngpKSArIGdlb21fYmFyKGFlcyh4PWFzLmZhY3RvcihpZCksIHk9dG90YWxfY2FtcGVvbmF0b3MsIGZpbGw9bmF0aW9uYWxpdHkueCksIHN0YXQ9ImlkZW50aXR5IiwgYWxwaGE9MC41KSArDQogIA0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAwLCB5ID0gOCwgeGVuZCA9IDMyLCB5ZW5kID0gOCksIGNvbG91ciA9ICJncmV5IiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAwLCB5ID0gNiwgeGVuZCA9IDMyLCB5ZW5kID0gNiksIGNvbG91ciA9ICJncmV5IiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAwLCB5ID0gNCwgeGVuZCA9IDMyLCB5ZW5kID0gNCksIGNvbG91ciA9ICJncmV5IiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAwLCB5ID0gMiwgeGVuZCA9IDMyLCB5ZW5kID0gMiksIGNvbG91ciA9ICJncmV5IiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICANCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gcmVwKG1heChjYW1wZW9uZXMkaWQpLDQpLCB5ID0gYygyLCA0LCA2LCA4KSwgbGFiZWwgPSBjKCIyIiwgIjQiLCAiNiIsICI4IikgLCBjb2xvcj0id2hpdGUiLCBzaXplPTMgLCBhbmdsZT0wLCBmb250ZmFjZT0iYm9sZCIsIGhqdXN0PTEpICsNCiAgDQogICBnZW9tX2JhcihhZXMoeD1hcy5mYWN0b3IoaWQpLCB5PXRvdGFsX2NhbXBlb25hdG9zLCBmaWxsPW5hdGlvbmFsaXR5LngpLCBzdGF0PSJpZGVudGl0eSIsIGFscGhhPTAuNSkgKw0KICB5bGltKC0xMCwyMSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwbG90Lm1hcmdpbiA9IHVuaXQocmVwKC0xLDQpLCAiY20iKSApICsNCiAgY29vcmRfcG9sYXIoKSArIA0KICBnZW9tX3RleHQoZGF0YT1sYWJlbF9jYW1wZW9uZXMsIGFlcyh4PWlkLCB5PTEwLCBsYWJlbD1kcml2ZXJSZWYsIGhqdXN0PWhqdXN0KSwgY29sb3I9IndoaXRlIiwgZm9udGZhY2U9ImJvbGQiLGFscGhhPTAuNiwgc2l6ZT0zLjUsIGFuZ2xlPSBsYWJlbF9jYW1wZW9uZXMkYW5nbGUsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQoNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMC43MCwgeSA9IC0xLCB4ZW5kID0gMi40NSwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMi42LCB5ID0gLTEsIHhlbmQgPSAzLjU1LCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDMuNjUsIHkgPSAtMSwgeGVuZCA9IDUuNDUsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gNS41NSwgeSA9IC0xLCB4ZW5kID0gNy4zNSwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSA3LjUsIHkgPSAtMSwgeGVuZCA9IDEwLjUwLCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDEwLjcsIHkgPSAtMSwgeGVuZCA9IDE5LjIwLCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDE5LjQsIHkgPSAtMSwgeGVuZCA9IDIwLjMsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMjAuNDUsIHkgPSAtMSwgeGVuZCA9IDIzLjQsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsgDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDIzLjY1LCB5ID0gLTEsIHhlbmQgPSAyNC4zNSwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKyANCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMjQuNjAsIHkgPSAtMSwgeGVuZCA9IDI3LCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDI3LjIsIHkgPSAtMSwgeGVuZCA9IDI5LjUsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsNCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMjkuNywgeSA9IC0xLCB4ZW5kID0gMzAuNSwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKyANCiAgZ2VvbV9zZWdtZW50KGRhdGE9Z3JpZF9jYW1wZW9uZXMsIGFlcyh4ID0gMzAuNywgeSA9IC0xLCB4ZW5kID0gMzEuNSwgeWVuZCA9IC0xKSwgY29sb3VyID0gIndoaXRlIiwgYWxwaGE9MSwgc2l6ZT0wLjMgLCBpbmhlcml0LmFlcyA9IEZBTFNFICkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YT1ncmlkX2NhbXBlb25lcywgYWVzKHggPSAzMS43LCB5ID0gLTEsIHhlbmQgPSAzMi41LCB5ZW5kID0gLTEpLCBjb2xvdXIgPSAid2hpdGUiLCBhbHBoYT0xLCBzaXplPTAuMyAsIGluaGVyaXQuYWVzID0gRkFMU0UgKSArDQogIGdlb21fc2VnbWVudChkYXRhPWdyaWRfY2FtcGVvbmVzLCBhZXMoeCA9IDMyLjcsIHkgPSAtMSwgeGVuZCA9IDMzLjUsIHllbmQgPSAtMSksIGNvbG91ciA9ICJ3aGl0ZSIsIGFscGhhPTEsIHNpemU9MC4zICwgaW5oZXJpdC5hZXMgPSBGQUxTRSApICsgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIndoaXRlIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KCBjb2xvdXIgPSAid2hpdGUiKSwgDQogICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIiwgY29sb3VyID0gImdyYXkxMyIpLA0KICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiICwgY29sb3VyID0gImdyYXkxMyIpLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIgLCBjb2xvdXIgPSAiZ3JheTEzIikpDQoNCg0KYGBgDQoNCg0KIyB0ZW1wbG9zIHkgdGllbXBvcyAodGVtcCAyMDIxKSBnbG9ibyBpbnRlcmFjdGl2bw0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCg0KY2FycmVyYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL3JhY2VzLmNzdiIpDQpjaXJjdWl0b3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NpcmN1aXRzLmNzdiIpDQoNCmNhcnJlcmFzXzIxIDwtIGZ1bGxfam9pbihjYXJyZXJhcyxjaXJjdWl0b3MsIGMoImNpcmN1aXRJZCIgPSAiY2lyY3VpdElkIikpICU+JQ0KICBmaWx0ZXIoeWVhcj09IjIwMjAiKSAlPiUNCiAgc2VsZWN0KHJvdW5kLCBuYW1lLngsIG5hbWUueSwgZGF0ZSwgbG9jYXRpb24sY291bnRyeSwgbGF0LCBsbmcsIGFsdCkgJT4lDQogIGFycmFuZ2Uocm91bmQpICU+JSANCiAgbXV0YXRlKHJvdW5kMiA9IHJvdW5kKSANCg0KY2FycmVyYXNfMjFfdjIgPC0gY2FycmVyYXNfMjFbLCBjKDEsIDQsIDEwLCAyLCAzLCA1LCA2LCA3LCA4LCA5KV0NCmNhcnJlcmFzXzIxX3YyIDwtIGNhcnJlcmFzXzIxX3YyJT4lICB1bml0ZSguICx2YXJpYWJsZXMsIGMoMSwgNSwgNyksIHNlcCA9ICI7ICIpDQoNCiNwcnVlYmFzIHBhcmEgbWFwYXMsIG5vIGVqZWN1dGFyIGRlIG1vbWVudG8NCiNsaWJyYXJ5KHdpZGdldGZyYW1lKQ0KI2xpYnJhcnkobGVhZmxldCkNCiNsIDwtIGxlYWZsZXQoKSAlPiUgc2V0VmlldyhsYXQgPSA0NS42MTU2MCwgbG5nID0gOS4yODExMTAsIHpvb209MSkNCiNmcmFtZVdpZGdldChsKSANCg0KI21hcGFDaXVkYWR5UHVlYmxvbWF5b3JpbmNpQWN1IDwtIGxlYWZsZXQoKSAlPiUNCiAjIHNldFZpZXcobG5nID0gLTAuMjQzNTkxLCBsYXQgPSAzOC44MjEsIHpvb20gPSA3KSAlPiUgDQogICNhZGRNYXJrZXJzKGxuZyA9IC0wLjI0MzU5MSwgbGF0ID0gMzguODIxICwgcG9wdXAgPSAiVmFsbCBkZSBHYWxsaW5lcmEiKSU+JQ0KICAjc2V0VmlldyhsbmcgPSAtMC40MTg1OTgsIGxhdCA9IDQwLjIwMTEsIHpvb20gPSA3KSAlPiUgDQogICNhZGRNYXJrZXJzKGxuZyA9IC0wLjQxODU5OCwgbGF0ID0gNDAuMjAxMSAsIHBvcHVwID0gIlZpbGxhaGVybW9zYSBkZWwgcmlvIikgJT4lIGFkZFRpbGVzKCkNCiNtYXBhQ2l1ZGFkeVB1ZWJsb21heW9yaW5jaUFjdQ0KDQojTUFQQSBERUwgTVVORE8gREUgTEEgT1NUSUEgTk8gVE9DQVIsIHBvbmdvIGNvbW8gY29tZW50YXJpbyBwYXJhIHF1ZSBubyB0YXJkZSB0YW50byBhbCBrbml0ZWFyDQoNCg0KZ2xvYm9fY2lyYyA8LWNyZWF0ZV9nbG9iZSgpICU+JSBnbG9iZV9wb3YoNDUuNjE1NjAsIDkuMjgxMTEwKSAlPiUgZ2xvYmVfYmFycyhjb29yZHMobGF0LCBsbmcsIGxhYmVsICA9IHZhcmlhYmxlcywgY29sb3IgPSByb3VuZDIpLCBkYXRhID0gY2FycmVyYXNfMjFfdjIpICAlPiUgc2NhbGVfYmFyc19jb2xvcigpDQojZ2xvYm9fY2lyYw0KDQpvYmpldG9zX25vX2JvcnJhciA8LSBjKCJ2aWN0b3JpYXNfY29uX25vbWJyZSIsICJuX2NhcnJlcmFzX25vbSIsICJtYXNfdmljdG9yaWFzIikNCnJtKGxpc3QgPSBscygpWyFscygpICVpbiUgb2JqZXRvc19ub19ib3JyYXJdKQ0KYGBgDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQpjaXJjdWl0b3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2NpcmN1aXRzLmNzdiIpDQp0aWVtcG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9sYXBfdGltZXMuY3N2IikNCmNhcnJlcmFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yYWNlcy5jc3YiKQ0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KDQpjaXJjdWl0b3NfZ3AgPC0gZnVsbF9qb2luKGNhcnJlcmFzLCBjaXJjdWl0b3MsIGMoImNpcmN1aXRJZCIgPSAiY2lyY3VpdElkIikpICNhc29jaW8gbGFzIGNhcnJlcmFzIGEgc3UgY2lyY3VpdG8NCnRpZW1wb3N2dWVsdGFfeF9jYXJyZXJhIDwtIGZ1bGxfam9pbihjaXJjdWl0b3NfZ3AsIHRpZW1wb3MsIGMgKCJyYWNlSWQiID0gInJhY2VJZCIpKSAjdGllbXBvIGRlIGxhcyB2dWVsdGFzIHBvciBjYWRhIGNhcnJlcmENCg0KdGllbXBvc3Z1ZWx0YV94X2NhcnJlcmEgPC0gZnVsbF9qb2luKHRpZW1wb3N2dWVsdGFfeF9jYXJyZXJhLCBwaWxvdG9zLCBjICgiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSAgc2VsZWN0KGNpcmN1aXRJZCwgbmFtZS55LCBkcml2ZXJJZCwgZHJpdmVyUmVmLCB0aW1lLnksIGxhcCxwb3NpdGlvbiwgeWVhciwgY291bnRyeSkgI2Z1c2lvbm8gY29uIGVsIGRmIGRlIHBpbG90b3MgcGFyYSBhc29jaWFyIGNhZGEgdnVlbHRhIGFsIG5vbWJyZSBkZWwgcGlsb3RvIHF1ZSBsYSBoaXpvDQoNCg0KI2NhbGN1bG8gZWwgcmVjb3JkIGRlIGNhZGEgY2lyY3VpdG8sIGZpbHRyYW5kbyBlbCBtaW5pbW8gZGUgbG9zIHRpZW1wb3MgZW4gY2FkYSBjaXJjdWl0bw0KcmVjb3JkX2RlX2NpcmN1aXRvIDwtIHRpZW1wb3N2dWVsdGFfeF9jYXJyZXJhICU+JSBncm91cF9ieShuYW1lLnkpICU+JSBzbGljZV9taW4odGltZS55LCBuPTEpDQoNCiNudW1lcm8gZGUgcmVjb3JkcyBkZSBjaXJjdWl0byBxdWUgdGllbmUgY2FkYSBwaWxvdG8NCnJlY29yZF94X3BpbG90byA8LSByZWNvcmRfZGVfY2lyY3VpdG8gJT4lIGdyb3VwX2J5KGRyaXZlcklkKSAlPiUgbXV0YXRlKG51bWVyb19yZWNvcmRzID0gc3VtKG4oKSkpICU+JSBzZWxlY3QoZHJpdmVySWQsIGRyaXZlclJlZiwgbnVtZXJvX3JlY29yZHMpICU+JSBkaXN0aW5jdChkcml2ZXJSZWYsIG51bWVyb19yZWNvcmRzKSAlPiUgYXJyYW5nZShkZXNjKG51bWVyb19yZWNvcmRzKSkNCg0KDQojIG1ldGVyIG1hcGEgZGVsIG11bmRvIGNvbiBsYSB1YmljYWNpb24gZGUgbG9zIGNpcmN1aXRvcyBlbiBsYSB0ZW1wb3JhZGEgMjAyMQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpvYmpldG9zX25vX2JvcnJhciA8LSBjKCJ2aWN0b3JpYXNfY29uX25vbWJyZSIsICJuX2NhcnJlcmFzX25vbSIsICJtYXNfdmljdG9yaWFzIikNCnJtKGxpc3QgPSBscygpWyFscygpICVpbiUgb2JqZXRvc19ub19ib3JyYXJdKQ0KDQpgYGANCg0KIyBDYXDDrXR1bG8gb3NjdXJvIGRlbCBkZXBvcnRlDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCiNjcmVvIGRmIGRlIG11ZXJ0ZXMgZGUgZm9ybXVsYSAxDQptdWVydGVzZjEgPC0gZGF0YS5mcmFtZSgNCiAgIm9yZGVuIiA9IDE6NDIsDQogICJkcml2ZXJSZWYiID0gYygiQ2hldCBNaWxsZXIiLCAiQ2FybCBTY2FyYWJvcm91Z2giLCAiT25vZnJlIE1hcmltb24iLCAiTWFubnkgQXl1bG8iLCAiQmlsbCBWdWtvdmljaCIsICJBbGJlcnRvIEFzY2FyaSIsIkV1Z2VuaW8gQ2FzdGVsbG90dGkiLCAiS2VpdGggQW5kcmV3cyIsICJQYXQgTydDb25ub3IiLCAiTHVpZ2kgTXVzc28iLCAiUGV0ZXIgQ29sbGlucyIsICJTdHVhcnQgTGV3aXMtRXZhbnMiLCAiSmVycnkgVW5zZXIiLCAiQm9iIENvcnRuZXIiLCAiSXZvciBCdWViIiwgIkNocmlzIEJyaXN0b3ciLCAiQWxhbiBTdGFjZXkiLCAiR2l1bGlvIENhYmlhbmNhIiwgIldvbGZnYW5nIHZvbiBUcmlwcyIsICJDYXJlbCBHb2RpbiBkZSBCZWF1Zm9ydCIsICJKb2huIFRheWxvciIsICJMb3JlbnpvIEJhbmRpbmkiLCAiQm9iIEFuZGVyc29uIiwgIkpvIFNjaGxlc3NlciIsICJHZXJoYXJkIE1pdHRlciIsICJQaWVycyBDb3VyYWdlIiwgIkpvY2hlbiBSaW5kdCIsICJKbyBTaWZmZXJ0IiwgIlJvZ2VyIFdpbGxpYW1zb24iLCAiRnJhbsOnb2lzIENldmVydCIsICJQZXRlciBSZXZzb24iLCAiSGVsbXV0aCBLb2luaWdnIiwgIk1hcmsgRG9ub2h1ZSIsICJUb20gUHJ5Y2UiLCAiUm9ubmllIFBldGVyc29uIiwgIlBhdHJpY2sgRGVwYWlsbGVyIiwgIkdpbGxlcyBWaWxsZW5ldXZlIiwgIlJpY2NhcmRvIFBhbGV0dGkiLCAiRWxpbyBkZSBBbmdlbGlzIiwgIlJvbGFuZCBSYXR6ZW5iZXJnZXIiLCAiQXlydG9uIFNlbm5hIiwgIkp1bGVzIEJpYW5jaGkiKSwNCiAgIm5hdGlvbmFsaXR5IiA9IGMoIkFtZXJpY2FuIiwgIkFtZXJpY2FuIiwgIkFyZ2VudGluZSIsICJBbWVyaWNhbiIsICJBbWVyaWNhbiIsICJJdGFsaWFuIiwiSXRhbGlhbiIsICJBbWVyaWNhbiIsICJBbWVyaWNhbiIsICJJdGFsaWFuIiwgIkJyaXRpc2giLCAiQnJpdGlzaCIsICJBbWVyaWNhbiIsICJBbWVyaWNhbiIsICJCcml0aXNoIiwgIkJyaXRpc2giLCAiQnJpdGlzaCIsICJJdGFsaWFuIiwgIkdlcm1hbiIsICJEdXRjaCIsICJCcml0aXNoIiwgIkl0YWxpYW4iICwgIkJyaXRpc2giLCAiRnJlbmNoIiwgIkdlcm1hbiIsICJCcml0aXNoIiwgIkF1c3RyaWFuIiwgIlN3aXNzIiwgIkJyaXRpc2giLCAiRnJlbmNoIiwgIkFtZXJpY2FuIiwgIkF1c3RyaWFuIiwgIkFtZXJpY2FuIiwgIkJyaXRpc2giLCAiU3dlZGlzaCIsICJGcmVuY2giLCAiQ2FuYWRpYW4iLCAiSXRhbGlhbiIsICJJdGFsaWFuIiwgIkF1c3RyaWFuIiwgIkJyYXppbGlhbiIsICJGcmVuY2giKSwNCiAgImZlY2hhX211ZXJ0ZSIgPSBjKDE5NTMsIDE5NTMsIDE5NTQsIDE5NTUsIDE5NTUsIDE5NTUsIDE5NTcsIDE5NTcsIDE5NTgsMTk1OCwxOTU4LDE5NTgsMTk1OSwxOTU5LDE5NTksMTk2MCwgMTk2MCwxOTYxLDE5NjEsMTk2NCwxOTY2LCAxOTY3LCAxOTY3LDE5NjgsMTk2OSwgMTk3MCwxOTcwLDE5NzEsMTk3MywxOTczLDE5NzQsMTk3NCwxOTc1LDE5NzcsMTk3OCwxOTgwLDE5ODIsMTk4MiwxOTg2LDE5OTQsMTk5NCwyMDE0KSkNCiNubyBwb25nbyBsYXMgY29taWxsYXMgZW4gbG9zIGHDsW9zIHBhcmEgcXVlIHNlIGNyZWVuIGRpcmVjdGFtZW50ZSBjb21vIG9ic2VydmFjaW9uZXMgbnVtZXJpY2FzDQoNCiNjcmVvIHVuIGRmIGNvbiB0b2RvcyBsb3MgYcOxb3MgcGFyYSBsdWVnbyBmdXNpb25hcmxvLCB5YSBxdWUgbm8gaGF5IG11ZXJ0ZXMgdG9kb3MgbG9zIGHDsW9zIA0KYW55b3MgPC0gZGF0YS5mcmFtZSgNCiAgIm9yZGVuIiA9IDE6NzEsDQogICJhw7FvIiA9IGMoMTk1MDoyMDIwKSkNCg0KI3N1bWF0b3JpbyBkZSBsYXMgbXVlcnRlcyBwb3IgYcOxbw0KbXVlcnRlc19hbnlvIDwtIG11ZXJ0ZXNmMSAlPiUgZ3JvdXBfYnkoZmVjaGFfbXVlcnRlKSAlPiUgbXV0YXRlKG11ZXJ0ZXN4YW55byA9IHN1bShuKCkpKSAlPiUgZGlzdGluY3QoZmVjaGFfbXVlcnRlLCBtdWVydGVzeGFueW8pIA0KDQojZnVzaW9ubyBsb3MgMiBkZnMgcGFyYSBxdWUgdGVuZ2EgZW4gY3VlbnRhIGxvcyBhw7FvcyBkb25kZSBubyBoYXkgbXVlcnRlcw0KbXVlcnRlc2YxX2ZpbmFsIDwtIGZ1bGxfam9pbihtdWVydGVzX2FueW8sIGFueW9zLCBjKCJmZWNoYV9tdWVydGUiID0gImHDsW8iKSkgJT4lIHNlbGVjdChmZWNoYV9tdWVydGUsbXVlcnRlc3hhbnlvKSAlPiUgYXJyYW5nZShmZWNoYV9tdWVydGUpDQoNCiNjb252aWVydG8gbG9zIE4vQSBlbiAwLCBlcyBkZWNpciwgY3VhbmRvIG5vIGhheSBvYnNlcnZhY2lvbmVzLCBoYSBoYWJpZG8gMCBtdWVydGVzDQptdWVydGVzZjFfZmluYWxbaXMubmEobXVlcnRlc2YxX2ZpbmFsKV0gPC0gMA0KDQojZ3JhZmljbyBkZSBsYXMgbXVlcnRlcyBwb3IgY2FkYSBhw7FvICsgbGEgdGVuZGVuY2lhIG5lZ2F0aXZhIGVhIGxvIGxhcmdvIGRlIGxhIGhpc3RvcmlhDQpnZ19tdWVydGVzIDwtIGdncGxvdChtdWVydGVzZjFfZmluYWwsIGFlcyh4ID0gZmVjaGFfbXVlcnRlLCB5ID0gbXVlcnRlc3hhbnlvICkpICsgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIndoaXRlIiwgY29sb3VyID0gIndoaXRlIikgKyBnZW9tX3Ntb290aChjb2xvdXIgPSAiY3lhbiIsIHNlID0gRkFMU0UpICsgbGFicyh4ID0gIkHDsW8iICwgeSA9ICJOw7ptZXJvIGRlIG11ZXJ0ZXMiKSAgKyB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIndoaXRlIiksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5MTMiKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5MTMiKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTIiLA0KICAgICAgICBjb2xvdXIgPSAid2hpdGUiKSwgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIikpICtsYWJzKGNvbG91ciA9ICJ3aGl0ZSIpICsgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTM4IiwNCiAgICBsaW5ldHlwZSA9ICJkb3R0ZWQiKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSBOQSksDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUsDQogICAgICAgIGhqdXN0ID0gMC41KSkgK2xhYnModGl0bGUgPSAiQWNjaWRlbnRlcyBtb3J0YWxlcyBwb3IgYcOxbyIpICsgZ2VvbV90ZXh0KGRhdGEgPSBkYXRhLmZyYW1lKHggPSAyMDA0LjEwNTIyNjQyODc1LCB5ID0gMC4yMzc0NTA1MTY5NDIyNDEsIA0KICAgIGxhYmVsID0gIlRlbmRlbmNpYSBuZWdhdGl2YSIpLCBtYXBwaW5nID0gYWVzKHggPSB4LCB5ID0geSwgDQogICAgbGFiZWwgPSBsYWJlbCksIGNvbG91ciA9ICJjeWFuIiwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgc2l6ZSA9IDMpDQoNCmdncGxvdGx5KGdnX211ZXJ0ZXMpDQoNCg0KDQpgYGANCg0KIyBbMS4gSW50cm9kdWNjacOzbl17LnZlcmRlY2l0b30NCg0KVGVuZW1vcyBwZW5zYWRvIGVsYWJvcmFyIGVsIHRyYWJham8gZW4gZXF1aXBvIHNvYnJlIEZvcm11bGEgMSwgdW5hIGNvbXBldGljacOzbiBkZSBsYSBxdWUgc29tb3MgbXV5IGFmaWNpb25hZG9zLCBlbnRyZSBvdHJhcyBjb3NhcyBwb3IgbGEgaW1wb3J0YW5jaWEgcXVlIHRpZW5lbiBsb3MgZGF0b3MgYSBsYSBob3JhIGRlIGZvcm1hbGl6YXIgbGFzIGVzdHJhdGVnaWFzIGVuIGxhIGNvbXBldGljacOzbi4gDQoNCg0KIyBSZW1hbmRvIGEgY29udHJhY29ycmllbnRlDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQojbWFzIHBvc2ljaW9uZXMgcmVtb250YWRhcyBlbiB1bmEgY2FycmVyYSBncmFuIHByZW1pbw0KDQp0aWVtcG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9sYXBfdGltZXMuY3N2IikNCmNhcnJlcmFzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9yYWNlcy5jc3YiKQ0KcmVzdWx0YWRvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvcmVzdWx0cy5jc3YiKQ0KY2lyY3VpdG9zIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiLi9kYXRvcy9jaXJjdWl0cy5jc3YiKQ0KcGlsb3RvcyA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3MvZHJpdmVycy5jc3YiKQ0KDQpyZXN1bHRhZG9zWywgYyg2LDkpXSA8LSBzYXBwbHkocmVzdWx0YWRvc1ssIGMoNiw5KV0sIGFzLm51bWVyaWMpICN0cmFuc2Zvcm1vIHZhcmlhYmxlcyBncmlkIHkgcG9zaXRpb25PcmRlciBlbiBudW1lcmljbw0Kc3RyKHJlc3VsdGFkb3MpICMgcGFyYSBjb21wcm9iYXJsbw0KDQoNCiNtYXlvcmVzIHJlbW9udGFkYXMgZGUgbGEgaGlzdG9yaWEsIHNlIHJlc3RhIHBvc2ljaW9uIGRlIHNhbGlkYSAtIHBvc2ljaW9uIGZpbmFsDQpwdWVzdG9zX3JlbW9udGFkb3MgPC0gcmVzdWx0YWRvcyAlPiUgbXV0YXRlKHJlbW9udGFkb3MgPSBncmlkIC0gcG9zaXRpb25PcmRlcikgJT4lIHNlbGVjdChyYWNlSWQsIGRyaXZlcklkLCBncmlkLCBwb3NpdGlvbk9yZGVyLCByZW1vbnRhZG9zKSANCg0KDQojZGUgdG9kYSBsYSBoaXN0b3JpYQ0KY2lyY3VpdG9zX2dwIDwtIGZ1bGxfam9pbihjYXJyZXJhcywgY2lyY3VpdG9zLCBjKCJjaXJjdWl0SWQiID0gImNpcmN1aXRJZCIpKSAlPiUgc2VsZWN0KGNpcmN1aXRJZCwgbmFtZS55LCByYWNlSWQsIHllYXIpDQoNCnB0b3NfcmVtb250X2NhcnJlcmEgPC0gaW5uZXJfam9pbihwdWVzdG9zX3JlbW9udGFkb3MsIGNpcmN1aXRvc19ncCkNCg0KcHVlc3Rvc19yZW1vbnRfcGlsb3RvIDwtIGZ1bGxfam9pbihwaWxvdG9zLCBwdG9zX3JlbW9udF9jYXJyZXJhLCBjKCJkcml2ZXJJZCIgPSAiZHJpdmVySWQiKSkgJT4lIHNsaWNlX21heChyZW1vbnRhZG9zLCBuPTEwKSAlPiUgc2VsZWN0KGRyaXZlcklkLCBkcml2ZXJSZWYsbmFtZS55LHllYXIsIHJhY2VJZCwgZ3JpZCwgcG9zaXRpb25PcmRlciwgcmVtb250YWRvcykNCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoNCiMgZGUgbGEgaGlzb3RvcmlhIHJlY2llbnRlDQpjaXJjdWl0b3NfZ3BfcmVjaWVudCA8LSBmdWxsX2pvaW4oY2FycmVyYXMsIGNpcmN1aXRvcywgYygiY2lyY3VpdElkIiA9ICJjaXJjdWl0SWQiKSkgJT4lIHNlbGVjdChjaXJjdWl0SWQsIG5hbWUueSwgcmFjZUlkLCB5ZWFyKSAlPiUgZmlsdGVyKHllYXIgPj0gMTk5NSkNCg0KcHRvc19yZW1vbnRfY2FycmVyYV9yZWNpZW50IDwtIGlubmVyX2pvaW4ocHVlc3Rvc19yZW1vbnRhZG9zLCBjaXJjdWl0b3NfZ3BfcmVjaWVudCkNCg0KcHVlc3Rvc19yZW1vbnRfcGlsb3RvX3JlY2llbnQgPC0gZnVsbF9qb2luKHBpbG90b3MsIHB0b3NfcmVtb250X2NhcnJlcmFfcmVjaWVudCwgYygiZHJpdmVySWQiID0gImRyaXZlcklkIikpICU+JSBzbGljZV9tYXgocmVtb250YWRvcywgbj0xMCkgJT4lIHNlbGVjdChkcml2ZXJJZCwgZHJpdmVyUmVmLCBuYW1lLnksIHllYXIscmFjZUlkLCBncmlkLCBwb3NpdGlvbk9yZGVyLCByZW1vbnRhZG9zKSAlPiUgc2xpY2UoMTo0LDY6OCwxMCkgJT4lIGFycmFuZ2UoZGVzYyhyZW1vbnRhZG9zKSkNCg0KZ2dyZW1vbnRhZG9zIDwtIGdncGxvdChwdWVzdG9zX3JlbW9udF9waWxvdG9fcmVjaWVudCwgYWVzKHggPSByZW9yZGVyKGRyaXZlclJlZiwgcmVtb250YWRvcyksIHJlbW9udGFkb3MpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIGNvb3JkX2ZsaXAoKSArIGxhYnMoeCA9ICJQaWxvdG9zIiwgeSA9ICJOwrogZGUgcHVlc3RvcyByZW1vbnRhZG9zIiApDQpnZ3JlbW9udGFkb3MNCg0Kb2JqZXRvc19ub19ib3JyYXIgPC0gYygidmljdG9yaWFzX2Nvbl9ub21icmUiLCAibl9jYXJyZXJhc19ub20iLCAibWFzX3ZpY3RvcmlhcyIpDQpybShsaXN0ID0gbHMoKVshbHMoKSAlaW4lIG9iamV0b3Nfbm9fYm9ycmFyXSkNCmBgYA0KDQoNCiMgQUxPTlNPIHZzIEhBTUlMVE9ODQoNCmBgYHtyLCBldmFsPVRSVUUsIGVjaG89VFJVRX0NCg0KI3NlIG5lY2VzaXRhIHRlbmVyIGNhcmdhZG8gIm5fY2FycmVyYXNfbm9tIiwgInZpY3Rvcmlhc19jb25fbm9tYnJlIg0KIzEyMzQNCmZvdG9zX0FMT192c19IQU0gPC0gYygiLi9pbWFnZW5lcy9waWxvdG9zL2Fsb25zby5wbmciLCAiLi9pbWFnZW5lcy9waWxvdG9zL2hhbWlsdG9uLnBuZyIpDQpmb3Rvc19lc3BfaW5nIDwtIGMoIi4vaW1hZ2VuZXMvcGFpc2VzL2VzcGFueWEucG5nIiwgIi4vaW1hZ2VuZXMvcGFpc2VzL3VrLnBuZyIpDQpuX2NhcnJlcmFzX2Fsb19oYW0gPC0gbl9jYXJyZXJhc19ub20gJT4lIGZpbHRlcihkcml2ZXJSZWYgJWluJSBjKCJhbG9uc28iLCAiaGFtaWx0b24iKSkNCg0Kbl92aWN0b3JpYXNfYWxvX2hhbSA8LSB2aWN0b3JpYXNfY29uX25vbWJyZSAlPiUgZmlsdGVyKGRyaXZlclJlZiAlaW4lIGMoImFsb25zbyIsICJoYW1pbHRvbiIpKQ0KDQphbG9fdnNfaGFtIDwtIGZ1bGxfam9pbihuX2NhcnJlcmFzX2Fsb19oYW0sIG5fdmljdG9yaWFzX2Fsb19oYW0sIGMoImRyaXZlclJlZiI9ICJkcml2ZXJSZWYiKSkgJT4lIHNlbGVjdCggZHJpdmVyUmVmLCBudW1lcm9fY2FycmVyYXMsIG5fdmljdG9yaWFzKSAlPiUgYWRkX2NvbHVtbihmb3Rvc19lc3BfaW5nLCBmb3Rvc19BTE9fdnNfSEFNKSANCg0KbGlicmFyeShndCkNCmFsb192c19oYW1fdGFibGEgPC0gYWxvX3ZzX2hhbSAlPiUgZ3QoKSAlPiUgdGV4dF90cmFuc2Zvcm0oIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoZm90b3NfZXNwX2luZykpLCBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6bG9jYWxfaW1hZ2UoeCwgaGVpZ2h0ID0gNTApfSkgJT4lIHRleHRfdHJhbnNmb3JtKCBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKGZvdG9zX0FMT192c19IQU0pKSwgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OmxvY2FsX2ltYWdlKHgsIGhlaWdodCA9IDEwMCl9KSAlPiUgdGFiX2hlYWRlcih0aXRsZSA9IG1kKCIqKkFsb25zbyB2cyBIYW1pbHRvbioqIiksIHN1YnRpdGxlID0gbWQoIkNvbXBhcmFjacOzbiIpKSAlPiUgICBjb2xzX2xhYmVsKA0KICAgIGRyaXZlclJlZiA9IGh0bWwoIiIpLA0KICAgIG51bWVyb19jYXJyZXJhcyA9IGh0bWwoIk7CuiBjYXJyZXJhcyIpLA0KICAgIG5fdmljdG9yaWFzID0gaHRtbCgiTsK6IHZpY3RvcmlhcyIpLA0KICAgIGZvdG9zX2VzcF9pbmcgPSBodG1sKCJQYcOtcyIpLA0KICAgIGZvdG9zX0FMT192c19IQU0gPSBodG1sKCIiKSkgJT4lICANCiAgdGFiX29wdGlvbnModGFibGUuYmFja2dyb3VuZC5jb2xvciA9ICJncmF5MTMiLCAgIHRhYmxlLmZvbnQuY29sb3IubGlnaHQgPSAiY3lhbiIpICU+JSANCiAgY29sc19hbGlnbihhbGlnbiA9ICJjZW50ZXIiLA0KICBjb2x1bW5zID0gZXZlcnl0aGluZygpKQ0KDQphbG9fdnNfaGFtX3RhYmxhDQpgYGANCg0KIyBBdWRpZW5jaWFzDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQojYXVkaWVuY2lhcw0KDQoNCmF1ZGllbmNpYXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2F1ZGllbmNpYXNGMS5jc3YiKQ0KDQoNCmdnX2F1ZGllbmNpYXMgPC0gZ2dwbG90KGF1ZGllbmNpYXMsIGFlcyh4PXllYXIsIHk9IG51bWVyb19lc3BlY3RhZG9yZXMpKSArDQogIGdlb21fc2VnbWVudCggYWVzKHg9eWVhciwgeGVuZCA9IHllYXIsIHk9MCwgeWVuZD0gbnVtZXJvX2VzcGVjdGFkb3JlcyAsIHNpemUgPSAiMSIpKSArDQogIGdlb21fcG9pbnQoIHNpemU9NSwgY29sb3I9ImJsdWUiLCBmaWxsPWFscGhhKCJjeWFuIiwgOCksIGFscGhhPTAuNywgc2hhcGU9MjEsIHN0cm9rZT0yKSArICANCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IHNlcSgyMDA0LCAyMDIwLCAxKSwNCiAgICBsaW1pdHMgPSBjKDIwMDMsIDIwMjEpKSArIGxhYnMoeCA9ICJBw7FvIiwgeSA9ICJOdW1lcm8gZGUgZXNwZWN0YWRvcmVzIiApICArIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiKSwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiKSkgKyB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIndoaXRlIiksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTIwIiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTIwIiksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIndoaXRlIiwNCiAgICAgICAgaGp1c3QgPSAwLjUpKSArbGFicyh0aXRsZSA9ICJFdm9sdWNpw7NuIGRlIGxhIGF1ZGllbmNpYSIsDQogICAgY29sb3VyID0gIndoaXRlIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNCkpICMrIHRyYW5zaXRpb25fcmV2ZWFsKG51bWVyb19lc3BlY3RhZG9yZXMpDQoNCmdncGxvdGx5KGdnX2F1ZGllbmNpYXMpDQoNCg0KYGBgDQoNCiMgUHJlc3VwdWVzdG9zDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQuZXh0cmE9J2FuZ2xlPTkwJywgZWNobyA9IFRSVUV9DQojcHJlc3VwdWVzdG9zDQoNCnByZXN1cHVlc3RvcyA8LSByZWFkX2V4Y2VsKCJkYXRvcy9wcmVzdXB1ZXN0b3MueGxzeCIpDQoNCmdnX3ByZXN1cCA8LSBnZ3Bsb3QocHJlc3VwdWVzdG9zLCBhZXMoeWVhciwgUHJlc3VwdWVzdG8sIGNvbG9yID0gRXNjdWRlcmlhKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9saW5lKCkgKyANCiAgbGFicyh4ID0gIkHDsW8iLCB5ID0gIlByZXN1cHVlc3RvIGVuIOKCrCIgKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IHNlcSgyMDE1LCAyMDIzLCAxKSwNCiAgICBsaW1pdHMgPSBjKDIwMTQsIDIwMjQpKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoIGJyZWFrcyA9IHNlcSgwLCA3MDAwMDAwMDAsIDEwMDAwMDAwMCksDQogICAgbGltaXRzID0gYygwLCA2MDAwMDAwMDApKSAgKyB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIndoaXRlIiwNCiAgICAgICAgbGluZXR5cGUgPSAiYmxhbmsiKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAid2hpdGUiLA0KICAgICAgICBsaW5ldHlwZSA9ICJibGFuayIpLCBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwNCiAgICAgICAgZmFjZSA9ICJib2xkIiwgY29sb3VyID0gImN5YW4iLCB2anVzdCA9IDAuNzUpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwNCiAgICAgICAgZmFjZSA9ICJib2xkIiwgY29sb3VyID0gImN5YW4iLCBoanVzdCA9IDAuNSwNCiAgICAgICAgdmp1c3QgPSAwLjc1KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwNCiAgICAgICAgY29sb3VyID0gImN5YW4iKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMywNCiAgICAgICAgZmFjZSA9ICJib2xkIiwgY29sb3VyID0gImN5YW4iKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIiwNCiAgICAgICAgY29sb3VyID0gIndoaXRlIiksIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIpLA0KICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiKSwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIpKSArbGFicyh0aXRsZSA9ICJQUkVTVVBVRVNUTyBERSBDQURBIEVRVUlQTyBQT1IgVEVNUE9SQURBIikgKyB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9IE5BKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9IE5BKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIiwNCiAgICAgICAgY29sb3VyID0gTkEpLCBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5MTMiLA0KICAgICAgICBjb2xvdXIgPSBOQSkpICsgdGhlbWUobGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIpLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIikpICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5MjAiLA0KICAgIGxpbmV0eXBlID0gInNvbGlkIiksIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXkxNSIsDQogICAgbGluZXR5cGUgPSAic29saWQiKSkNCiANCmdncGxvdGx5KGdnX3ByZXN1cCkgI3BhcmEgcXVlIHNlYSBpbnRlcmFjdGl2bw0KYGBgDQoNCg0KIyBtYXBhIGRlIGNvcm9wbGV0YXMgZGUgcGlsb3RvcyBwb3IgcGFpcyAocG9yIHRlcm1pbmFyKQ0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KI0VTVE8gUVVFIFZBIEVOIENPTUVOVEFSSU9TIFZBIEZVRVJBDQoNCnBpbG90b3MgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICIuL2RhdG9zL2RyaXZlcnMuY3N2IikNCg0KbmFjaW9uYWxpZGFkIDwtIHBpbG90b3MgJT4lIGdyb3VwX2J5KG5hdGlvbmFsaXR5KSAlPiUgbXV0YXRlKG51bWVyb19jb21wYXRyaW90YXMgPSBzdW0obigpKSkgJT4lIGRpc3RpbmN0KG51bWVyb19jb21wYXRyaW90YXMpICU+JSBhcnJhbmdlKGRlc2MobnVtZXJvX2NvbXBhdHJpb3RhcykpICU+JSANCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJCcml0aXNoIiwgIlVuaXRlZCBLaW5nZG9tIikgJT4lIA0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkFtZXJpY2FuIiwgIlVuaXRlZCBTdGF0ZXMiKSAlPiUgDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiSXRhbGlhbiIsICdJdGFseScpICU+JSANCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJGcmVuY2giICwgJ0ZyYW5jZScpICU+JSANCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJHZXJtYW4iICwgJ0dlcm1hbnknKSAlPiUgDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiQnJhemlsaWFuIiAsICdCcmF6aWwnKSAlPiUgDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiQXJnZW50aW5lIiAsICdBcmdlbnRpbmEnKSAlPiUgDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiU3dpc3MiICwgJ1N3aXR6ZXJsYW5kJykgJT4lIA0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkJlbGdpYW4iICwgJ0JlbGdpdW0nKSAlPiUgDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiU291dGggQWZyaWNhbiIgLCAnU291dGggQWZyaWNhJykgJT4lIA0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkphcGFuZXNlIiAsICdKYXBhbicpICU+JSANCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJBdXN0cmFsaWFuIiAsICdBdXN0cmFsaWEnKSAlPiUNCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJEdXRjaCIgLCAnTmV0aGVybGFuZHMnKSAlPiUNCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJTcGFuaXNoIiAsICdTcGFpbicpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkF1c3RyaWFuIiAsICdBdXN0cmlhJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiQ2FuYWRpYW4iICwgJ0NhbmFkYScpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIlN3ZWRpc2giICwgJ1N3ZWRlbicpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkZpbm5pc2giICwgJ0ZpbmxhbmQnKSAlPiUNCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJOZXcgWmVhbGFuZGVyIiAsICdOZXcgWmVhbGFuZCcpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIk1leGljYW4iICwgJ01leGljbycpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIklyaXNoIiAsICdJcmVsYW5kJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiRGFuaXNoIiAsICdEZW5tYXJrJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiUG9ydHVndWVzZSIgLCAnUG9ydHVnYWwnKSAlPiUNCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJNb25lZ2FzcXVlIiAsICdGcmFuY2UnKSAlPiUNCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJSaG9kZXNpYW4iICwgJ1ppbWJhYndlJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiVXJ1Z3VheWFuIiAsICdVcnVndWF5JykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiUnVzc2lhbiIgLCAnUnVzc2lhJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiQ29sb21iaWFuIiAsICdDb2xvbWJpYScpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIlZlbmV6dWVsYW4iICwgJ1ZlbmV6dWVsYScpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkVhc3QgR2VybWFuIiAsICdHZXJtYW4nKSAlPiUNCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJJbmRpYW4iICwgJ0luZGlhJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiVGhhaSIgLCAnVGhhaWxhbmQnKSAlPiUNCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJQb2xpc2giICwgJ1BvbGFuZCcpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIk1vbmVnYXNxdWUiICwgJ0ZyYW5jZScpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkh1bmdhcmlhbiIgLCAnSHVuZ2FyeScpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkN6ZWNoIiAsICdDemVjaCBSZXAuJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiTWFsYXlzaWFuIiAsICdNYWxheXNpYScpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkNoaWxlYW4iICwgJ0NoaWxlJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiTGllY2h0ZW5zdGVpbmVyIiAsICdTd2l0emVybGFuZCcpICU+JQ0KICBzdHJfcmVwbGFjZV9hbGwoLiwgIkFtZXJpY2FuLUl0YWxpYW4iICwgJ1VuaXRlZCBTdGF0ZXMnKSAlPiUNCiAgc3RyX3JlcGxhY2VfYWxsKC4sICJBcmdlbnRpbmUtSXRhbGlhbiIgLCAnQXJnZW50aW5hJykgJT4lDQogIHN0cl9yZXBsYWNlX2FsbCguLCAiSW5kb25lc2lhbiIgLCAnSW5kb25lc2lhJykNCg0KcGFpc2VzX25vcm1hbGVzIDwtIGMoIlVuaXRlZCBLaW5nZG9tIiwgIlVuaXRlZCBTdGF0ZXMiLCAiSXRhbHkiLCAiRnJhbmNlIiwgIkdlcm1hbnkiLCAiQnJhemlsIiwgIkFyZ2VudGluYSIsICJTd2l0emVybGFuZCIsICJCZWxnaXVtIiwgIlNvdXRoIEFmcmljYSIsICJKYXBhbiIsICJBdXN0cmFsaWEiLCAiTmV0aGVybGFuZHMiLCAiU3BhaW4iLCAiQXVzdHJpYSIsICJDYW5hZGEiLCAiU3dlZGVuIiwgIkZpbmxhbmQiLCAiTmV3IFplYWxhbmQiLCAiTWV4aWNvIiwgIklyZWxhbmQiLCAiRGVubWFyayIsICJQb3J0dWdhbCIsICJGcmFuY2UiLCAiWmltYmFid2UiLCAiVXJ1Z3VheSIsICJSdXNzaWEiLCAiQ29sb21iaWEiLCAiVmVuZXp1ZWxhIiwgIkdlcm1hbnkiLCAiSW5kaWEiLCAiVGhhaWxhbmQiLCAiUG9sYW5kIiwgIkh1bmdhcnkiLCAiQ3plY2ggUmVwLiIsICJNYWxheXNpYSIsICJDaGlsZSIsICJTd2l0emVybGFuZCIsICJVbml0ZWQgU3RhdGVzIiwgIkFyZ2VudGluYSIsICJJbmRvbmVzaWEiICkNCg0KbmFjaW9uYWxpZGFkIDwtIHBpbG90b3MgJT4lIGdyb3VwX2J5KG5hdGlvbmFsaXR5KSAlPiUgbXV0YXRlKG51bWVyb19jb21wYXRyaW90YXMgPSBzdW0obigpKSkgJT4lIGRpc3RpbmN0KG51bWVyb19jb21wYXRyaW90YXMpICU+JSBhcnJhbmdlKGRlc2MobnVtZXJvX2NvbXBhdHJpb3RhcykpICU+JSBhZGRfY29sdW1uKHBhaXNlc19ub3JtYWxlcykgJT4lICBncm91cF9ieShwYWlzZXNfbm9ybWFsZXMpICU+JSBtdXRhdGUodG90YWxfcGlsb3RvcyA9IHN1bShudW1lcm9fY29tcGF0cmlvdGFzKSkgJT4lICBkaXN0aW5jdChwYWlzZXNfbm9ybWFsZXMsIHRvdGFsX3BpbG90b3MpDQoNCg0KbGlicmFyeSh0bWFwKQ0KZGF0YShXb3JsZCkNCndvcmxkIDwtIFdvcmxkOyBybShXb3JsZCkNCg0Kd29ybGQgPC0gd29ybGRbISh3b3JsZCRuYW1lICVpbiUgYygnR3JlZW5sYW5kJywgJ0FudGFyY3RpY2EnKSksXQ0KDQpwaWxvdG9zX3Bvcl9wYWlzZXMgPC0gZnVsbF9qb2luKG5hY2lvbmFsaWRhZCwgd29ybGQsIGMoICJwYWlzZXNfbm9ybWFsZXMiID0gIm5hbWUiKSkgDQoNCnBpbG90b3NfcG9yX3BhaXNlcyRjb3VudHJ5IDwtIE5VTEwNCg0KcGlsb3Rvc19wb3JfcGFpc2VzW2lzLm5hKHBpbG90b3NfcG9yX3BhaXNlcyldIDwtIDANCg0KZ2dfcGlsb3Rvc19wb3JfcGFpc2VzIDwtIGdncGxvdChkYXRhID0gcGlsb3Rvc19wb3JfcGFpc2VzLCBhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSkpICsgZ2VvbV9zZigpICsNCiAgICAgICBsYWJzKHRpdGxlID0gIlBpbG90b3MgcG9yIHBhw61zIiwNCiAgICAgICAgICAgIGNhcHRpb24gPSAiTWVub3IgaW50ZW5zaWRhZCBkZSBjb2xvciBlbiBhcXVlbGxvcyBwYWlzZXMgY29uIG3DoXMgcGlsb3RvcyIpDQoNCmdnX3BpbG90b3NfcG9yX3BhaXNlcyA8LSBnZ19waWxvdG9zX3Bvcl9wYWlzZXMgKyBnZW9tX3NmKGFlcyhmaWxsID0gdG90YWxfcGlsb3RvcykpICsgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoY29sb3VyID0gIndoaXRlIiksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJibGFuayIpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAiYmxhbmsiKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gImJsYW5rIiksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJncmF5MTMiKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwNCiAgICAgICAgY29sb3VyID0gIndoaXRlIiwgaGp1c3QgPSAwLjUpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIndoaXRlIiksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIpLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXkxMyIpLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiZ3JheTEzIikpICtsYWJzKGZpbGwgPSAiTsKqIGRlIHBpbG90b3MiKSArIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXkxMyIpLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JheTEzIikpICsgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSBOQSksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChsaW5ldHlwZSA9ICJzb2xpZCIpLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChsaW5ldHlwZSA9ICJzb2xpZCIpKSArIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJ3aGl0ZSIsIG1pZCA9ICJwaW5rIiwgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IC4wMikNCg0KYGBgDQoNCg0KIyBQSUxPVE9TIFBPUiBQQcONUyAoTUFQQSkgIHsudGFic2V0fQ0KDQojIyBNYXBhDQoNCmBgYHtyfQ0KDQpnZ3Bsb3RseShnZ19waWxvdG9zX3Bvcl9wYWlzZXMpDQoNCmBgYA0KDQoNCiMjIFRhYmxhDQpgYGB7cn0NCm5hY2lvbmFsaWRhZCAlPiUgZ3QoKSAlPiUgdGFiX2hlYWRlcih0aXRsZSA9IG1kKCIqKlBpbG90b3MgcG9yIGNhZGEgcGHDrXMqKiIpKSAlPiUgY29sc19sYWJlbCgNCiAgICBwYWlzZXNfbm9ybWFsZXMgPSBodG1sKCJQYWlzIiksDQogICAgdG90YWxfcGlsb3RvcyA9IGh0bWwoIk7CuiBwaWxvdG9zIikpICU+JSAgDQogIHRhYl9vcHRpb25zKHRhYmxlLmJhY2tncm91bmQuY29sb3IgPSAiZ3JheTEzIiwgdGFibGUuZm9udC5jb2xvci5saWdodCA9ICJjeWFuIikNCg0KDQoNCg0KYGBgDQoNCg0KIyAuDQojIyAqKlRIRSBQTEFOKioNCg0KYGBge3IsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0NCmxpYnJhcnkobWVtZSkNCiNteV9mb3RvIDwtICJodHRwczovL2UwMC1lbG11bmRvLnVlY2RuLmVzL2Fzc2V0cy9tdWx0aW1lZGlhL2ltYWdlbmVzLzIwMTcvMDUvMTIvMTQ5NDU4OTkzNDYzMDYuanBnIg0KI21lbWUobXlfZm90bywgIk1VWSBUUkFOUVVJTE9TIiwgIlNFIFZJRU5FIFRSQUJBSkFaTyIsIHNpemUgPSAyICwgY29sb3IgPSAiYmx1ZSIsIHZqdXN0ID0gMS4wNSkNCg0KYGBgDQoNCiMgMi4gRGF0b3MNCg0KSGVtb3MgZW5jb250cmFkbyBlbiBba2FnZ2xlXShodHRwczovL3d3dy5rYWdnbGUuY29tLykgYmFzdGFudGVzIGNvbmp1bnRvcyBkZSBkYXRvcyBjb24gbG9zIHF1ZSBwb2RlciB0cmFiYWphciwgcGVybyBlc3BlY2lhbG1lbnRlIFtlc3RlXShodHRwczovL3d3dy5rYWdnbGUuY29tL3JvaGFucmFvL2Zvcm11bGEtMS13b3JsZC1jaGFtcGlvbnNoaXAtMTk1MC0yMDIwKSwgcXVlIHBvc2VlIGdyYW4gdmFyaWVkYWQgZGUgZGF0b3MgZW4gbG8gcmVmZXJlbnRlIGEgcGlsb3RvcywgcmVzdWx0YWRvcywgY2lyY3VpdG9zLCB0aWVtcG9zLCBldGMuLi4gQ29uc2lkZXJhbW9zIHF1ZSBwYXJhIGVtcGV6YXIgYSB0cmFiYWphciBzZXLDoSBzdWZpY2llbnRlLCB5IGVuIGZ1bmNpw7NuIGRlIGNvbW8gdmF5YW1vcyBkaXJpZ2llbmRvIGVsIHRyYWJham8sIGJ1c2NhcmVtb3MgZGlmZXJlbnRlcyBjb25qdW50byBkZSBkYXRvcyBjb24gbG9zIHF1ZSBhcG95YXJub3MuDQoNCiMgMy4gVHJhYmFqb3MgZW4gbG9zIHF1ZSBub3MgdmFtb3MgYSBiYXNhcg0KDQpDb24gbG9zIGRhdG9zIHF1ZSBoZW1vcyBlbmNvbnRyYWRvLCBleGlzdGVuIHVuYSBzZXJpZSBkZSBjw7NkaWdvcyBxdWUgeWEgdHJhYmFqYW4gY29uIGVzdG9zIGRhdG9zLCBlc3BlY2lhbG1lbnRlIFtlc3RlXShodHRwczovL3d3dy5rYWdnbGUuY29tL2VrcmVtYmF5YXIvZm9ybXVsYS0xLTcwdGgtYW5uaXZlcnNhcnkpLCBxdWUgaGEgY29uc2VndWlkbyByZWFsaXphciBhbsOhbGlzaXMgY29uIGVzdGUgY29uanVudG8gZGUgZGF0b3MgeSB2YXJpYXMgaWx1c3RyYWNpb25lcyBtdXkgbGxhbWF0aXZhcywgcG9yIGxvIHF1ZSBwb2RyZW1vcyB0b21hcmxvIGNvbW8gcmVmZXJlbmNpYSBkdXJhbnRlIGVsIGluaWNpbyBkZWwgdHJhYmFqbw0KDQo+ICJOYWRpZSBlcyBtw6FzIHLDoXBpZG8gcXVlIGVsIG5hbm8iDQoNCg0KDQpgYGB7cn0NCg0KbGlicmFyeShtYWdpY2spDQpjb2NoZTE5NTAgPC0gaW1hZ2VfcmVhZCgiLi9pbWFnZW5lcy9jb2NoZXMvMTk1MC5qcGciKSAlPiUgaW1hZ2Vfc2NhbGUoLiwgIjUwMCIpICU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5NTAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUxOTYwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzE5NjAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5NjAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUxOTcwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzE5NzAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5NzAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUxOTgwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzE5ODAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5ODAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUxOTkwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzE5OTAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjE5OTAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUyMDA1IDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzIwMDUuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjIwMDUiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGUyMDIwIDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvY29jaGVzLzIwMjAuanBnIikgJT4lIGltYWdlX3NjYWxlKC4sICI1MDAiKSU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjIwMjAiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGh3ZXN0IiwgY29sb3IgPSAid2hpdGUiKQ0KY29jaGVzIDwtIGMoY29jaGUxOTUwLCBjb2NoZTE5NjAsIGNvY2hlMTk3MCwgY29jaGUxOTgwLCBjb2NoZTE5OTAsIGNvY2hlMjAwNSwgY29jaGUyMDIwKQ0KDQppbWFnZV9hbmltYXRlKGltYWdlX3NjYWxlKGNvY2hlcyksIGZwcyA9IDAuNSkNCmBgYA0KDQo=